{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# \n",
"\n",
"# Exploring first and second derivatives with Julia\n",
"\n",
"To get started, we load the `MTH229` package:"
],
"id": "c4226837-cadc-454f-959d-2d312ba7e38e"
},
{
"cell_type": "code",
"execution_count": 1,
"metadata": {},
"outputs": [],
"source": [
"using MTH229\n",
"using Plots\n",
"plotly()"
],
"id": "78098870"
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Recall, when `MTH229` is loaded, the same prime notation of mathematics\n",
"is available in `Julia` for indicating derivatives of functions (through\n",
"`ForwardDiff`).\n",
"\n",
"## Quick background\n",
"\n",
"Read about this material here: [Exploring first and second derivatives\n",
"with Julia](http://mth229.github.io/first-second-derivatives.html).\n",
"\n",
"This assignment looks at the relationship between a function, $f(x)$,\n",
"and its first and second derivatives: $f'(x)$ and $f''(x)$. The basic\n",
"relationship can be summarized (though the devil is in the details) by:\n",
"\n",
"- If the first derivative is *positive* on $(a,b)$ then the function\n",
" is *increasing* on $(a,b)$.\n",
"\n",
"- If the second derivative is *positive* on $(a,b)$ then the function\n",
" is *concave up* on $(a,b)$.\n",
"\n",
"(The “devil” here is that the converse statements are usually - but not\n",
"always - true.)\n",
"\n",
"Some key definitions are:\n",
"\n",
"- A **critical** point of $f$ is a value in the domain of $f(x)$ for\n",
" which the derivative is $0$ or undefined. These are often—but **not\n",
" always**—where $f(x)$ has a local maximum or minimum.\n",
"\n",
"- An **inflection point** of $f$ is a value in the domain of $f(x)$\n",
" where the concavity of $f$ *changes*. (These are *often*—but **not\n",
" always**—where $f''(x)=0$.)\n",
"\n",
"These two relationships and definitions are put to use to characterize\n",
"*local extrema* of a function via one of two “derivative” tests:\n",
"\n",
"- The **first derivative test**: This states that if $c$ is a critical\n",
" point of $f(x)$ then if $f'(x)$ changes sign from $+$ to $-$ at $c$\n",
" then $f(c)$ is a local maximum and if $f'(x)$ changes sign from $-$\n",
" to $+$ then $f(c)$ is a local minimum. If there is no sign change,\n",
" then $f(c)$ is neither a local minimum or maximum.\n",
"\n",
"- The **second derivative test**: This states that if $c$ is a\n",
" critical point of $f(x)$ and $f''(c) > 0$ then $f(c)$ is a local\n",
" minimum and if $f''(c) < 0$ then $f(c)$ is a local maximum. The test\n",
" says nothing about the case $f''(c) = 0$.\n",
"\n",
"------------------------------------------------------------------------\n",
"\n",
"We investigate these concepts in `Julia` both graphically and\n",
"numerically.\n",
"\n",
"For the graphical exploration, the `plotif` function from the `MTH229`\n",
"package is quite useful.\n",
"\n",
"It is used to plot a function `f` using two colors; the color choice\n",
"depending on whether the second function, `g` is non-negative or not.\n",
"\n",
"This function can be used to graphically illustrate where the graph of\n",
"`f` is *positive*, *increasing*, or *concave up*: `plotif(f, f, a, b)`\n",
"will show a different color when $f(x)$ is *positive*,\n",
"`plotif(f, f', a, b)` will show a different color when $f(x)$ is\n",
"*increasing*, and `plotif(f, f'', a, b)` will show a different color\n",
"when $f(x)$ is *concave up*. For example, here we see where the\n",
"following `f` is increasing:"
],
"id": "d6cfee47-238d-4b81-8de1-5bc407a6a833"
},
{
"cell_type": "code",
"execution_count": 3,
"metadata": {},
"outputs": [
{
"output_type": "display_data",
"metadata": {},
"data": {
"text/html": [
""
]
}
}
],
"source": [
"f(x) = 1 + cos(x) + cos(2x)\n",
"plotif(f, f', 0, 2pi) # color increasing\n",
"plot!(zero)"
],
"id": "6c372ee8"
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### `fzeros`\n",
"\n",
"Once eyes are trained to identify zeros, critical points, or inflection\n",
"points of a function, we can use numeric methods to zoom in on more\n",
"accurate values.\n",
"\n",
"Recall, `fzero(f, a, b)` will find a zero of `f` **if** `[a,b]` is a\n",
"*bracketing* interval (`f` takes different signs at the endpoints); and\n",
"`fzero(f, c)` will try to find a zero *near* `c`.\n",
"\n",
"These two methods are incorporated into the convenience function\n",
"`fzeros(f, a, b)` which *attempts* to identify all zeros within\n",
"`[a, b]`.\n",
"\n",
"It is called like `plot` with a function and two values indicating the\n",
"interval to scan:"
],
"id": "57823a57-27aa-433d-9a1a-6a61d8e54b7c"
},
{
"cell_type": "code",
"execution_count": 4,
"metadata": {},
"outputs": [
{
"output_type": "display_data",
"metadata": {},
"data": {
"text/plain": [
"4-element Vector{Float64}:\n",
" 1.5707963267948966\n",
" 2.0943951023931953\n",
" 4.1887902047863905\n",
" 4.71238898038469"
]
}
}
],
"source": [
"zs = fzeros(f, 0, 2pi)"
],
"id": "b63d1a9a"
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The `fzeros` function returns a container of values, which may, of\n",
"course, be empty. Above we assigned the name `zs` to these values.\n",
"\n",
"There are times when applying a function to the returned values is\n",
"desired. The “dot” makes this easy. Here we apply `f` to the values in\n",
"`zs` and expect to see values near `0`:"
],
"id": "a0fe0f25-2bbc-4b1a-bc78-897080d78bd5"
},
{
"cell_type": "code",
"execution_count": 5,
"metadata": {},
"outputs": [
{
"output_type": "display_data",
"metadata": {},
"data": {
"text/plain": [
"4-element Vector{Float64}:\n",
" 0.0\n",
" -2.220446049250313e-16\n",
" 3.3306690738754696e-16\n",
" -2.220446049250313e-16"
]
}
}
],
"source": [
"f.(zs)"
],
"id": "c60d3ee1"
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"------------------------------------------------------------------------\n",
"\n",
"If our task was to get *all* critical points of `f` in the interval\n",
"$(0, 2\\pi)$, then `fzeros` is an easy-to-use choice: As `f` is\n",
"continuously differentiable, all critical points are given by solving\n",
"$f'(x)=0$:"
],
"id": "574becb4-b6ab-457c-a56c-4fc445601d2e"
},
{
"cell_type": "code",
"execution_count": 6,
"metadata": {},
"outputs": [
{
"output_type": "display_data",
"metadata": {},
"data": {
"text/plain": [
"5-element Vector{Float64}:\n",
" 0.0\n",
" 1.8234765819369751\n",
" 3.141592653589793\n",
" 4.459708725242611\n",
" 6.283185307179586"
]
}
}
],
"source": [
"fzeros(f', 0, 2pi)"
],
"id": "4a9e89f4"
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### `sign_chart`\n",
"\n",
"These same values are also identified by `sign_chart` (which uses\n",
"`fzeros` behind the scenes) and indicates whether the function changes\n",
"sign at the identified zeros (or undefined values):"
],
"id": "caafa36d-b6e3-48b4-9d9b-52d9a9ae5aab"
},
{
"cell_type": "code",
"execution_count": 7,
"metadata": {},
"outputs": [
{
"output_type": "display_data",
"metadata": {},
"data": {
"text/html": [
"
5-element Vector{NamedTuple{(:zero_oo_NaN, :sign_change)}}:\n", " (zero_oo_NaN = 0.0, sign_change = an endpoint)\n", " (zero_oo_NaN = 1.82347658194, sign_change = - to +)\n", " (zero_oo_NaN = 3.14159265359, sign_change = + to -)\n", " (zero_oo_NaN = 4.45970872524, sign_change = - to +)\n", " (zero_oo_NaN = 6.28318530718, sign_change = an endpoint)" ] } } ], "source": [ "sign_chart(f', 0, 2pi)" ], "id": "d3c40684" }, { "cell_type": "markdown", "metadata": {}, "source": [ "This output shows, for example, that $f'(x)$ is positive on\n", "$(1.82\\dots, 3.14\\dots)$ and again on $(4.45\\dots, 6.28\\dots)$. This\n", "could be used to conclude where $f(x)$ is *increasing*.\n", "\n", "------------------------------------------------------------------------\n", "\n", "If our task is to get all *inflection* points of `f` in the interval,\n", "then the `sign_chart` function is helpful, as inflection points are\n", "points in the domain where the concavity changes:" ], "id": "43219e1d-4c07-4c12-aec7-f3bc0dd83a37" }, { "cell_type": "code", "execution_count": 8, "metadata": {}, "outputs": [ { "output_type": "display_data", "metadata": {}, "data": { "text/html": [ "
4-element Vector{NamedTuple{(:zero_oo_NaN, :sign_change)}}:\n", " (zero_oo_NaN = 0.866676087105, sign_change = - to +)\n", " (zero_oo_NaN = 2.45335016275, sign_change = + to -)\n", " (zero_oo_NaN = 3.82983514443, sign_change = - to +)\n", " (zero_oo_NaN = 5.41650922007, sign_change = + to -)" ] } } ], "source": [ "sign_chart(f'', 0, 2pi)" ], "id": "d4b9ccbb" }, { "cell_type": "markdown", "metadata": {}, "source": [ "As the sign changes at each of the identified values, all `4` are\n", "inflection points.\n", "\n", "### Careful\n", "\n", "The convenient `fzeros` and `sign_chart` functions are only *pretty*\n", "good at finding all the zeros over the interval. For some functions –\n", "especially those cooked up by clever math professors – the choice of\n", "interval can lead to `fzeros` finding fewer than is mathematically\n", "possible. The functions should be used in combination with a plot and\n", "with as narrow an interval specified, as reasonable.\n", "\n", "------------------------------------------------------------------------" ], "id": "9d6a6d2b-89c0-483e-b89e-6e9f7ff8490b" }, { "cell_type": "code", "execution_count": 9, "metadata": {}, "outputs": [], "source": [ "# Your commands go here" ], "id": "488f5441" } ], "nbformat": 4, "nbformat_minor": 5, "metadata": { "kernelspec": { "name": "julia-1.11", "display_name": "Julia 1.11.2", "language": "julia", "path": "/Users/jverzani/Library/Jupyter/kernels/julia-1.11" }, "language_info": { "name": "julia", "file_extension": ".jl", "mimetype": "application/julia", "version": "1.11.2" } } }