{
  "cells": [
     {"cell_type":"markdown","source":"<h1>The Roots package</h1>","metadata":{"internals":{"slide_type":"subslide","slide_helper":"subslide_end"},"slideshow":{"slide_type":"slide"},"slide_helper":"slide_end"}},
{"cell_type":"markdown","source":"<p>The <code>Roots</code> 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 <code>fzero</code>, which through multiple dispatch and keyword arguments can handle many different cases.</p>","metadata":{}},
{"cell_type":"markdown","source":"<p>We will use <code>Plots</code> for plotting.</p>","metadata":{}},
{"outputs":[],"cell_type":"code","source":["using Roots  \nusing Plots"],"metadata":{},"execution_count":null},
{"cell_type":"markdown","source":"<h2>Bracketing</h2>","metadata":{"internals":{"slide_type":"subslide","slide_helper":"subslide_end"},"slideshow":{"slide_type":"slide"},"slide_helper":"slide_end"}},
{"cell_type":"markdown","source":"<p>For a function $f: R \\rightarrow R$ a <em>bracket</em> 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.</p>","metadata":{}},
{"cell_type":"markdown","source":"<p>That is, given <code>f&#40;a&#41; * f&#40;b&#41; &lt; 0</code>, a value <code>c</code> with <code>a &lt; c &lt; b</code> can be found where either <code>f&#40;c&#41; &#61;&#61; 0.0</code> or at least <code>f&#40;prevfloat&#40;c&#41;&#41; * f&#40;nextfloat&#40;c&#41;&#41; &lt;&#61; 0</code>.</p>","metadata":{}},
{"cell_type":"markdown","source":"<p>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):</p>","metadata":{}},
{"outputs":[{"output_type":"execute_result","data":{"text/plain":"Plot(...)","image/png":"[encoded data, 17864 characters]"},"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":"<p>The basic function call specifies a bracket using either two values or vector notation:</p>","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},
{"cell_type":"markdown","source":"<p>For this function we see that <code>f&#40;x&#41; &#61;&#61; 0.0</code>.</p>","metadata":{}},
{"cell_type":"markdown","source":"<hr />","metadata":{}},
{"cell_type":"markdown","source":"<p>Next consider $f(x) = \\sin(x)$. A known root is $\\pi$. Trignometry tells us that $[\\pi/2, 3\\pi/2]$ will be a bracket:</p>","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":"<p>This value of <code>x</code> does not produce <code>f&#40;x&#41; &#61;&#61; 0.0</code>, however, it is as close as can be:</p>","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},
{"cell_type":"markdown","source":"<p>That is, at <code>x</code> the function is changing sign.</p>","metadata":{}},
{"cell_type":"markdown","source":"<p>The algorithm identifies discontinuities, not just zeros:</p>","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":"<p>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.</p>","metadata":{}},
{"cell_type":"markdown","source":"<p>The endpoints can even be infinite:</p>","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},
{"cell_type":"markdown","source":"<h2>Using an initial guess</h2>","metadata":{"internals":{"slide_type":"subslide","slide_helper":"subslide_end"},"slideshow":{"slide_type":"slide"},"slide_helper":"slide_end"}},
{"cell_type":"markdown","source":"<p>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 <code>fzero</code> 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.</p>","metadata":{}},
{"cell_type":"markdown","source":"<p>The default algorithm is modeled after an algorithm used for <a href=\"http://www.hpl.hp.com/hpjournal/pdfs/IssuePDFs/1979-12.pdf\">HP-34 calculators</a>. 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.</p>","metadata":{}},
{"cell_type":"markdown","source":"<p>For example, the answer to our initial problem is near 1. Given this, we can find the zero with:</p>","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},
{"cell_type":"markdown","source":"<p>For the polynomial $f(x) = x^3 - 2x - 5$, an initial guess of 2 seems reasonable:</p>","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},
{"cell_type":"markdown","source":"<p>For even more precision, <code>BigFloat</code> numbers can be used</p>","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},
{"cell_type":"markdown","source":"<h3>Higher order methods</h3>","metadata":{"internals":{"slide_type":"subslide"},"slideshow":{"slide_type":"subslide"},"slide_helper":"slide_end"}},
{"cell_type":"markdown","source":"<p>The default call to <code>fzero</code> 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 (<a href=\"http://en.wikipedia.org/wiki/Steffensen&#39;s_method\">Steffensen</a>), 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 <code>order</code> argument:</p>","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":"<p>The latter shows that zeros need not be simple zeros (i.e. $f'(x) = 0$, if defined) to be found.</p>","metadata":{}},
{"cell_type":"markdown","source":"<p>To investigate the algorithm and its convergence, the argument <code>verbose&#61;true</code> may be specified.</p>","metadata":{}},
{"cell_type":"markdown","source":"<p>For some functions, adjusting the default tolerances may be necessary to achieve convergence. These include <code>abstol</code> and <code>reltol</code>, which are used to check if <code>norm&#40;f&#40;x&#41;&#41; &lt;&#61; max&#40;abstol, norm&#40;x&#41;*reltol&#41;</code>; <code>xabstol</code>, <code>xreltol</code>, to check if <code>norm&#40;x1-x0&#41; &lt;&#61; max&#40;xabstol, norm&#40;x1&#41;*xreltol&#41;</code>; and <code>maxevals</code> and <code>maxfnevals</code> to limit the number of steps in the algorithm or function calls.</p>","metadata":{}},
{"cell_type":"markdown","source":"<p>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.</p>","metadata":{}},
{"cell_type":"markdown","source":"<hr />","metadata":{}},
{"cell_type":"markdown","source":"<p>For a classic example where a large second derivative is the issue, we have $f(x) = x^{1/3}$:</p>","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},
{"cell_type":"markdown","source":"<p>However, the default finds the root here, as a bracket is identified:</p>","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},
{"cell_type":"markdown","source":"<p>Order 8 illustrates that sometimes the stopping rules can be misleading and checking the returned value is always a good idea:</p>","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":"<p>The algorithm rapidly marches off towards infinity so the relative tolerance $|x| \\cdot \\epsilon$ is large compared to the far-from zero $f(x)$.</p>","metadata":{}},
{"cell_type":"markdown","source":"<hr />","metadata":{}},
{"cell_type":"markdown","source":"<p>This example illustrates that the default <code>fzero</code> call is more forgiving to an initial guess. The devilish function defined below comes from a <a href=\"http://people.sc.fsu.edu/~jburkardt/cpp_src/test_zero/test_zero.html\">test suite</a> of difficult functions. The default method finds the zero starting at 0:</p>","metadata":{}},
{"outputs":[{"output_type":"execute_result","data":{"text/plain":"Plot(...)","image/png":"[encoded data, 20968 characters]"},"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":"<p>Whereas, with <code>order&#61;n</code> methods fail. For example,</p>","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":"<p>Basically the high order oscillation can send the proxy tangent line off in nearly random directions. The default method can be fooled here too.</p>","metadata":{}},
{"cell_type":"markdown","source":"<hr />","metadata":{}},
{"cell_type":"markdown","source":"<p>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:</p>","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},
{"cell_type":"markdown","source":"<p>Whereas, </p>","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},
{"cell_type":"markdown","source":"<p>A graph shows the issue. We have overlayed a 15 steps of Newton's method, the other algorithms being somewhat similar:</p>","metadata":{}},
{"outputs":[{"output_type":"execute_result","data":{"text/plain":"Plot(...)","image/png":"[encoded data, 23324 characters]"},"metadata":{"image/png":{"height":480,"width":600}},"execution_count":null}],"cell_type":"code","source":[""],"metadata":{},"execution_count":null},
{"cell_type":"markdown","source":"<p>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.</p>","metadata":{}},
{"cell_type":"markdown","source":"<h2>Finding more than one zero</h2>","metadata":{"internals":{"slide_type":"subslide","slide_helper":"subslide_end"},"slideshow":{"slide_type":"slide"},"slide_helper":"slide_end"}},
{"cell_type":"markdown","source":"<p>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 <code>fzeros&#40;f, a, b&#41;</code>. 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:</p>","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":"<h2>Classical methods</h2>","metadata":{"internals":{"slide_type":"subslide","slide_helper":"subslide_end"},"slideshow":{"slide_type":"slide"},"slide_helper":"slide_end"}},
{"cell_type":"markdown","source":"<p>The package provides some classical methods for root finding: <code>newton</code>, <code>halley</code>, and <code>secant_method</code>. We can see how each works on a problem studied by Newton himself. Newton's method uses the function and its derivative:</p>","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},
{"cell_type":"markdown","source":"<p>To see the algorithm in progress, the argument <code>verbose&#61;true</code> may be specified. </p>","metadata":{}},
{"cell_type":"markdown","source":"<p>The secant method needs two starting points, here we start with 2 and 3:</p>","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},
{"cell_type":"markdown","source":"<p>Halley's method has cubic convergence, as compared to Newton's quadratic convergence. It uses the second derivative as well:</p>","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},
{"cell_type":"markdown","source":"<p>For many function, the derivatives can be computed automatically. The <code>ForwardDiff</code> package provides a means. This package wraps the process into an operator, <code>D</code> which returns the derivative of a function <code>f</code> (for simple-enough functions):</p>","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},
{"cell_type":"markdown","source":"<p>Or for Halley's method</p>","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},
{"cell_type":"markdown","source":"<p>Specifying the derivative(s) can be skipped, the functions will default to the above calls.</p>","metadata":{}},
{"cell_type":"markdown","source":"<h2>Finding critical points</h2>","metadata":{"internals":{"slide_type":"subslide","slide_helper":"subslide_end"},"slideshow":{"slide_type":"slide"},"slide_helper":"slide_end"}},
{"cell_type":"markdown","source":"<p>The <code>D</code> 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:</p>","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},
{"cell_type":"markdown","source":"<p>For more complicated expressions, <code>D</code> will not work. In this example, we have a function $f(x, \\theta)$ that models the flight of an arrow on a windy day:</p>","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},
{"cell_type":"markdown","source":"<p>The total distance flown is when <code>flight&#40;x&#41; &#61;&#61; 0.0</code> for some <code>x &gt; 0</code>: This can be solved for different <code>theta</code> with <code>fzero</code>. In the following, we note that <code>log&#40;a/&#40;a-x&#41;&#41;</code> will have an asymptote at <code>a</code>, so we start our search at <code>a-5</code>:</p>","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},
{"cell_type":"markdown","source":"<p>To see the trajectory if shot at 45 degrees, we have:</p>","metadata":{}},
{"outputs":[{"output_type":"execute_result","data":{"text/plain":"Plot(...)","image/png":"[encoded data, 18236 characters]"},"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},
{"cell_type":"markdown","source":"<p>To maximize the range we solve for the lone critical point of <code>howfar</code> within the range. The derivative can not be taken automatically with <code>D</code>. 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:</p>","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},
{"cell_type":"markdown","source":"<p>This shows the differences in the trajectories:</p>","metadata":{}},
{"outputs":[{"output_type":"execute_result","data":{"text/plain":"Plot(...)","image/png":"[encoded data, 29156 characters]"},"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}
    ],
 "metadata": {
  "language_info": {
   "name": "julia",
   "version": "0.4"
  },
 "kernelspec": {
   "display_name": "Julia 0.4.0",
   "language": "julia",
   "name": "julia-0.4"
  }

 },
 "nbformat": 4,
 "nbformat_minor": 0

}
