using MTH229
using Plots
plotly()
Plots.PlotlyBackend()
A notebook for this material: ipynb
We load the MTH229
package and plotting package for this section:
using MTH229
using Plots
plotly()
Plots.PlotlyBackend()
This project explores the relationship between a function, \(f(x)\) and its first and second derivatives.
The following definitions describe features of functions over an interval:
There are similar definitions for negative, decreasing, and concave down.
You may be more familiar with these implications for functions with derivatives:
Pay attention to the difference between positive and non-negative. For example, an increasing, differentiable function on I=(a,b) is only guaranteed to have a non-negative derivative – not a positive derivative on I.
A common task in this subject is identifying where a function is positive, negative, zero, or undefined.
A theoretical tool is the intermediate value theorem which can be used to say that a continuous function has only one sign (positive or negative) between adjacent zeros. That is, if \(a\) and \(b\) are zeros of \(f(x)\), a continuous function with say \(a < b\) and there is no \(c\) with \(a < c < b\) such that \(f(c) = 0\), then \(f(x)\) for \(x\) in \((a,b)\) is either always positive or always negative.
This gives a technique to identify where a function is positive:
Wherever one of the test points is positive, the interval between the two adjacent zeros will correspond to an interval where the function is positive.
If the function is not continuous, say at a finite set of points, then include the points of discontinuity in the consideration. In fact, only discontinuities where the function jumps over the \(y\) axis need consideration.
We can graphically identify when a function is positive with the strategy above. Consider the following function over the interval \([-2, 1]\):
\[ f(x) = e^{-x} \cdot (\sin(3x) + \sin(5x)). \]
A plot shows roughly that this function is positive between \(-2\) and \(-0.8\), save near \(-1.57\) where \(f\) is \(0\) and between \(0.0\) and \(0.8\).
f(x) = exp(-x) * (sin(3x) + sin(5x))
plot(f, -2, 1)
plot!(zero)
The MTH229
package loads a convenience function, plotif
, to show the graph of f
highlighting when a second function, g
is nonnegative. In this case, to see where f
is non-negative, we want g
to be f
:
plotif(f, f, -2, 1)
The plotif
function shows when g
is non-negative, not just positive, so wouldn’t show a different color for the graph near \(-1.57\) where f
is zero but doesn’t cross the \(x\) axis.
find_zeros
functionWe have discussed two means to find zeros of a function \(f\):
when the zero is between two values which form a bracketing interval. The zero in the graph above between \(-1\) and \(-0.5\) is an example. Such zeros are readily identified through bisection
when a zero is near a value, such as these four which are near \(-1.5\), \(-0.75\), \(0.0\) and \(0.8\). Such zeros may typically be found with Newton’s method (or find_zero
)
The Roots
package, exported with MTH229
, provides a convenience function, find_zeros
, which uses bisection or fzero
to identify heuristically all zeros in an interval \([a,b]\). It is easy to use: the interval is specified by pairing off the interval:
find_zeros(f, (-2, 1)) # note the s in find_zeros
4-element Vector{Float64}:
-1.570796326120076
-0.7853981633974483
0.0
0.7853981633974483
The algorithm isn’t guaranteed to always work the way bisection is, but works fairly well to identify all the zeros except for cases where there are many zeros in the interval or the interval chosen is too wide. (A bracketing interval specified to bisection may be infinite, but such wide intervals can be problematic with find_zeros
, though can work in some cases.)
Here is another example, find the zeros of \(f(x) = e^x - x^4\) over \([-10, 10]\):
f(x) = exp(x) - x^4
find_zeros(f, -10, 10)
3-element Vector{Float64}:
-0.8155534188089606
1.4296118247255556
8.613169456441398
The above also shows the interval can also be specified using two values, as is done with plot
.
A related problem might be find all zeros of \(f(x) = e^x - x^6\). Where should one look to ensure all of the zeros are identified? Too big an interval and the values of \(e^x\) will be infinite (numerically) and that may cause problems. Too small an interval and zeros may be excluded. In this case a bit of analysis can help: any zero must be bigger than \(-1\), as to the left of \(-1\) the exponential is smaller than \(1\) and the polynomial bigger than \(1\) in absolute value. Further, as exponentials eventually dominate polynomials, the interval need not be too large. We could quickly check that \(e^{20}\) is bigger than \(20^6\) but instead we just try a somewhat larger right limit:
f(x) = exp(x) - x^6
find_zeros(f, (-1, 50))
3-element Vector{Float64}:
-0.8656497043253173
1.2268886960394931
16.99888735229605
The algorithm used by find_zeros
relies on both bisection and a method like Newton’s method. The bisection implementation will pick up on places where the function changes sign, even if not continuous. In the example below, the two vertical asymptotes at \(3\) and \(4\) are found:
f(x) = (x-1)*(x-2) / ((x-3)*(x-4))
= find_zeros(f, -10, 10) zs
4-element Vector{Float64}:
1.0
2.0
2.9999999999999996
3.9999999999999996
The values at the zs
can easily be checked using broadcasting:
f.(zs) # using the broadcasting syntax -- the dot.
4-element Vector{Float64}:
-0.0
0.0
4.503599627370491e15
-1.351079888211149e16
Programmatically, the filter
function might be used to screen these out, or in this example a comprehension:
in zs if abs(f(z)) <= 10] [z for z
2-element Vector{Float64}:
1.0
2.0
However, for our usage below it is quite helpful that these points are identified.
sign_chart
functionThe technique above to find where a function is positive can be automated if find_zeros
is used to find the zeros. This is done in sign_chart
.
For example,
f(x) = exp(x) - x^6
sign_chart(f, -1, 20)
3-element Vector{NamedTuple{(:zero_oo_NaN, :sign_change)}}: (zero_oo_NaN = -0.865649704325, sign_change = - to +) (zero_oo_NaN = 1.22688869604, sign_change = + to -) (zero_oo_NaN = 16.9988873523, sign_change = - to +)
The output shows how the sign changes at the identified zeros (or other points). In this case we can infer that the function is positive on \((-0.8656\dots, 1.22688869\dots)\) and again on \((16.998887\dots, \infty)\).
Returning to the example function
f(x) = exp(-x) * (sin(3x) + sin(5x))
f (generic function with 1 method)
we apply sign_chart
over \((-2,1)\):
sign_chart(f, -2, 1)
4-element Vector{NamedTuple{(:zero_oo_NaN, :sign_change)}}: (zero_oo_NaN = -1.57079632612, sign_change = + to +) (zero_oo_NaN = -0.785398163397, sign_change = + to -) (zero_oo_NaN = 0.0, sign_change = - to +) (zero_oo_NaN = 0.785398163397, sign_change = + to -)
The output matches the graph produced above with plotif
. The zero at \(-1.57\dots\) does not have a sign change, the others do in agreement with the graph.
How many zeros are found between \(-2\) and \(1\) for
\[ f(x) = e^{-x/2} \cdot (\sin(11x) + \sin(13x)) \]
What is the largest value identified in \([-2,1]\) by find_zeros
for the function
\[ f(x) = e^{-x/2} \cdot (\sin(11x) + \sin(13x)) \]
For \(f(x) = e^{-x/2} \cdot (\sin(11x) + \sin(13x))\) Consider the output of sign_chart(f, -2, 1)
. What is the sign of \(f\) at \(-1\)?
Consider \(f(x) = \sin(3x) + \sin(5x)\) over \([-2, 1]\). What does sign_chart
identify at the smallest zero?
As seen, the plotif
function loaded with the MTH229
package makes it easy for us to highlight when a function is non negative, as it shows in a separate color when the second function is non-negative.
For example, consider \(f(x) = x^3 - 2x - 1/2\).
This graph shows where \(f(x)\) is positive over \((-2,2)\):
f(x) = x^3 - 2x - 1/2
plotif(f, f, -2, 2)
plot!(zero)
In this graph, we estimate graphically that the intervals \((-1.2, 0.2)\) and \((1.5, 2)\) are where \(f\) is positive within this viewing window.
If we change the screening function to the derivative of \(f(x)\), then our graph will show when the function is increasing (or flat):
plotif(f, f', -2, 2)
Again, we eyeball from the graph to estimate that this occurs on \((-2, -0.8)\) and \((0.8, 2)\).
Using when the second derivative is non-negative indicates where f
is concave up:
plotif(f, f'', -2, 2)
We can see the function is concave up on \((0, 2)\) and changes concavity at the inflection point \(x=0\).
Graphically identify when the function \(f(x) = x^x\) is increasing on \((0,2)\)
Graphically identify when the function \(f(x) = \sqrt{|1 - x^2|}\) is increasing on the interval \([-2, 2]\).
Graphically identify when the function \(f(x) = x^2 \cdot e^{-x}\) is concave up on the interval \((0,10)\).
Consider the function below:
f(x) = x < -1 ? -x - 1 : x > 1 ? x - 1 : 0
What does the output of plotif(f, f', -5, 5)
show?
The find_zeros
function can readily identify when some function is zero (or undefined). It can be used, as seen, to find zeros. However, if passed f'
it will identify critical points. When passed f''
it will find when \(f''(x) = 0\) (or undefined). Such points are candidates for inflection points, though a check on whether the concavity changes is necessary to say such is an inflection point.
In the following we use scatter!
to show these values on the graph.
f(x) = exp(-x/2) * (sin(3x) + sin(5x))
= find_zeros(f, -2, 1)
zs = find_zeros(f', -2, 1)
cps = find_zeros(f'', -2, 1)
ips
plot(f, -2, 1)
scatter!(zs, f.(zs), markercolor="blue", markersize=7)
scatter!(cps, f.(cps), markercolor="red", markersize=3)
scatter!(ips, f.(ips), markercolor="green", markershape=:diamond)
An attempt to distinguish the points using color, marker size and shape is made, showing that the value at \(-1.5707963267\dots\) is both a zero and a critical point.
The graph also shows that the candidates for inflection points are indeed inflection points. This could also be verified with sign_chart
where the second derivative changes sign at each:
sign_chart(f'', -2, 1)
5-element Vector{NamedTuple{(:zero_oo_NaN, :sign_change)}}: (zero_oo_NaN = -1.86089851657, sign_change = - to +) (zero_oo_NaN = -1.33370970092, sign_change = + to -) (zero_oo_NaN = -0.739296253922, sign_change = - to +) (zero_oo_NaN = -0.0524780565601, sign_change = + to -) (zero_oo_NaN = 0.645452569404, sign_change = - to +)
Suppose we only know indirect things about a function \(f(x)\), how much can we say?
We previously mentioned two basic relationships:
If \(f'(x) > 0\) on an interval \((a,b)\) then the function \(f(x)\) is increasing on \((a,b)\). (It may also increase when \(f'(x)=0\), but it isn’t guaranteed.)
If \(f''(x) > 0\) on \((a,b)\) then the function \(f(x)\) is concave up on \((a,b)\).
Similar statements can be made for negative values of the derivative and second derivative.
For example, lets suppose we know that the derivative of \(f(x)\) is \(f'(x) = \exp(x)\). What can we say about \(f(x)\) on the interval \((0,4)\)?
We make two graphs:
fp(x) = exp(x)
plotif(fp, fp, 0, 4)
plotif(fp, fp', 0, 4)
From the graphs we see that \(f'(x)\) is always positive and increasing.
From the first fact (\(f'(x) > 0\)) we know that \(f(x)\) is increasing on this interval.
From the second fact (\(f'(x)\) is increasing) we know that \(f(x)\) is concave up on this interval.
Do we know any specific values, or even less ambitiously, when \(f(x)\) is positive? The answer must be no – we could always add a constant to \(f(x)\) and not effect its derivative.
Now suppose we have a different \(f(x)\). In this case all we know is the second derivative is \(f''(x) = x^2 - 2x\). What can we say about \(f(x)\) on the interval \((-1,3)\)?
A plot to see where the second derivative is positive will show that this \(f''(x)\) is positive on \((-1, 0)\) and \((2,3)\):
fpp(x) = x^2 - 2x
plotif(fpp, fpp, -1, 3)
This means \(f(x)\) is concave up on these same intervals.
Can we tell if our unknown \(f(x)\) is increasing? Nope, we have no such ability. We could always add a term \(mx\) to \(f(x)\) and keep the same second derivative. So we can’t tell if the function \(f(x)\) is increasing and we can’t tell where the function \(f(x)\) is positive, but we can say where it is concave up when we all we know is a second derivative.
You know that \(f'(x) = |x|\). Over \([-1,1]\) where if \(f(x)\) increasing and where is it concave up?
Suppose \(f'(x) = (x^4 - x^2 + 2)/(x^4 - 2x^2 + 1)\). When is \(f(x)\) increasing on \((-2, 2)\)?
If \(f'(x) = \tan(x) - 3x/2\). When is \(f(x)\) concave down on the interval \((-\pi/3, \pi/3)\)?
The first- and second-derivative tests are a means to classify if a critical point is also a local extrema. A local extrema will always correspond to a critical point – but not necessarily vice versa. There are two theorems that ensure a critical point will be a local extrema:
The first derivative test
If \(c\) is a critical point and \(f'(x)\) changes sign at \(x=c\), then \((c,f( c))\) will be a local extrema. (If the sign change is from positive to negative, it will be a local maximum.) If there is no sign change, the critical point is not a local extrema.
The second derivative test
If \(c\) is a critical point and \(f''(x) \neq 0\) then \((c,f( c))\) will be a local extrema. If \(f''( c) > 0\) this will be a local minimum and if \(f''( c) < 0\) a local maximum. (Nothing conclusive can be said when \(f''(c)=0\).)
For example, let \(f(x) = 2\sin(x) + \cos(2x)\). Find all critical points on \([0, 2\pi]\).
As \(f(x)\) is everywhere differentiable, these critical points would be where the derivative is \(0\). A plot helps us identify how many and roughly where:
f(x) = 2sin(x) + cos(2x)
plot(f', 0, 2pi)
We see four: one near \(0.8\), one near \(1.5\), one near \(2.5\) and one near \(5\).
As explained, we could use find_zeros
to identify these more precisely:
= find_zeros(f', 0, 6) cps
4-element Vector{Float64}:
0.5235987755982988
1.5707963267948966
2.617993877991494
4.71238898038469
From the graph of f'
we can see at the first critical point the derivative is changing sign from positive to negative at the first one (hence a local maximum), and this alternates as we go along.
However, we can do this numerically, using the sign_chart
function.
sign_chart(f', 0, 4)
3-element Vector{NamedTuple{(:zero_oo_NaN, :sign_change)}}: (zero_oo_NaN = 0.523598775598, sign_change = + to -) (zero_oo_NaN = 1.57079632679, sign_change = - to +) (zero_oo_NaN = 2.61799387799, sign_change = + to -)
So by the first derivative test we have a max, min, max, min which we see when we plot f
:
plot(f, 0, 2pi)
To get the same classification from the second derivative test, we evaluate \(f''(x)\) at these four critical points:
''.(cps) f
4-element Vector{Float64}:
-3.0000000000000004
2.0
-2.9999999999999982
6.0
Where using the dot broadcasts f''
over all the values in cps
.
The following graphic is to illustrate why the second derivative test works as it does:
plot(f, 0, 2pi; legend=false, linewidth=4)
= find_zeros(f', 0, 2pi)
cps plot_parabola!(c, fc, fppc) = plot!(x -> fc + fppc * (x - c)^2/2, c-3/4, c+3/4; linewidth=2)
plot_parabola!.(cps, f.(cps), f''.(cps))
current()
Each critical point is matched with a parabola with quadratic term one-half the second derivative. We can see at a relative minimum, then the parabola opens upward just like the graph of f
; at a relative maximum, the approximating parabola opens downward.
Let \(f'(x) = x^4 - 4x^2 + 1\). Classify all relative extrema of \(f(x)\) on the interval \((-1, 1)\).
Let fp(x) = (2x-1)/cbrt(x^2 - x - 2)^2
. Over the interval \((-1.5,1.5)\) identify all relative maxima and minima of \(f(x)\).
Suppose, \(f(x)\) has a critical at \(0\) and \(1\). If possible, classify them as relative maximum or minimum assuming \(f''(x) = 1 - 2x - \sin(x)\)
Julia
when generated
Julia
version:
VERSION
v"1.10.4"
Packages and versions:
using Pkg
Pkg.status()
Status `~/work/mth229.github.io/mth229.github.io/Project.toml`
[a2e0e22d] CalculusWithJulia v0.2.6
[7073ff75] IJulia v1.25.0
[b964fa9f] LaTeXStrings v1.3.1
[ebaf19f5] MTH229 v0.3.2
[91a5bcdd] Plots v1.40.4
[f27b6e38] Polynomials v4.0.11
[438e738f] PyCall v1.96.4
[612c44de] QuizQuestions v0.3.23
[295af30f] Revise v3.5.14
[f2b01f46] Roots v2.1.5
[24249f21] SymPy v2.1.1
[56ddb016] Logging