14. Local extrema, saddle points, and the second-derivative test

📖 Reading · 11 min
💡 Every code box below is live — edit it and hit Run.

§3.5 found a single-variable function's peaks and valleys by locating where f'(x)=0, then using f'' to tell max from min. This lesson runs the identical program one dimension up — except that in two variables, a new possibility appears that has no one-variable analogue at all: a point that's simultaneously a maximum in one direction and a minimum in another.

Critical points

A point (a,b) is a critical point of f(x,y) if \nabla f(a,b)=\vec0 (both f_x(a,b)=0 and f_y(a,b)=0) or if either partial derivative fails to exist there. Exactly as in §3.5, every local extremum must occur at a critical point — if \nabla f\ne\vec0 at a point, §10.5 showed the directional derivative toward \nabla f is strictly positive, meaning f is still increasing in some direction, ruling out a local max or min right there.

But not every critical point is an extremum. This is where two variables genuinely diverge from one: §10.0 already previewed the culprit — the saddle point, at the origin of f(x,y)=x^2-y^2. There, \nabla f(0,0)=\langle0,0\rangle, a bona fide critical point, yet the function increases along the x-axis and decreases along the y-axis simultaneously — neither a max nor a min, just a point where the surface bends up one way and down the other, like the middle of a horse's saddle or a mountain pass.

The second-derivative test

Define the discriminant:

D(x,y)=f_{xx}f_{yy}-(f_{xy})^2

using §10.2's second-order partials (Clairaut's theorem guarantees f_{xy}=f_{yx}, so it doesn't matter which mixed partial is used). At a critical point (a,b):

\begin{cases} D>0\text{ and }f_{xx}>0&\text{local minimum}\\ D>0\text{ and }f_{xx}<0&\text{local maximum}\\ D<0&\text{saddle point}\\ D=0&\text{inconclusive} \end{cases}

Why the sign of D separates extrema from saddles: D measures whether the surface curves the same way in every direction (D>0, producing a genuine bowl or dome — an extremum) or opposite ways along different directions (D<0, a saddle). This is a two-variable version of the second-derivative test's original logic (§3.5): there, f''>0 meant concave up in the only available direction; here, curvature can disagree across directions, and D is exactly the quantity that detects that disagreement.

Once D>0 is established (curving the same way everywhere), f_{xx}'s sign alone decides max versus min — the direct analogue of §3.5's single-variable rule (f''>0 minimum, f''<0 maximum), because D>0 guarantees f_{yy} shares f_{xx}'s sign too (if they disagreed, f_{xx}f_{yy} would be negative, forcing D<0).

Doing it in Python

Finding and classifying every critical point of f(x,y)=x^3-3xy+y^3:

import sympy as sp

x, y = sp.symbols('x y')
f = x**3 - 3*x*y + y**3

f_x = sp.diff(f, x)
f_y = sp.diff(f, y)
critical_points = sp.solve([f_x, f_y], [x, y])

f_xx = sp.diff(f, x, 2)
f_yy = sp.diff(f, y, 2)
f_xy = sp.diff(f_x, y)

for pt in critical_points:
    if not all(v.is_real for v in pt):
        continue   # skip complex (non-physical) critical points
    subs = {x: pt[0], y: pt[1]}
    D = f_xx.subs(subs) * f_yy.subs(subs) - f_xy.subs(subs)**2
    fxx_val = f_xx.subs(subs)
    if D > 0 and fxx_val > 0:
        kind = "local minimum"
    elif D > 0 and fxx_val < 0:
        kind = "local maximum"
    elif D < 0:
        kind = "saddle point"
    else:
        kind = "inconclusive"
    print(f"{pt}: D={D}, f_xx={fxx_val}  ->  {kind}")

Visualizing the saddle behavior directly by sampling f(x,y)=x^2-y^2 along both axes through its critical point:

def f(x, y):
    return x**2 - y**2

print(f"{'along x-axis':>20} {'along y-axis':>20}")
for t in (-1, -0.5, 0, 0.5, 1):
    print(f"f({t:>4},0) = {f(t,0):>8}      f(0,{t:>4}) = {f(0,t):>8}")
print("\nincreases moving along x, decreases moving along y -- a saddle")

Confirming the discriminant sign directly explains the mixed behavior, by comparing f_{xx} and f_{yy}'s signs at a saddle versus a genuine extremum:

import sympy as sp

x, y = sp.symbols('x y')

saddle = x**2 - y**2
bowl = x**2 + y**2

for name, f in (("saddle", saddle), ("bowl", bowl)):
    f_xx = sp.diff(f, x, 2)
    f_yy = sp.diff(f, y, 2)
    f_xy = sp.diff(f, x, y)
    D = f_xx * f_yy - f_xy**2
    print(f"{name}: f_xx={f_xx}, f_yy={f_yy}, D={D}")

Worked example

Find and classify all real critical points of f(x,y)=x^3-3xy+y^3.

f_x=3x^2-3y=0\ \Longrightarrow\ y=x^2\qquad f_y=-3x+3y^2=0\ \Longrightarrow\ x=y^2

Substitute: $x=(x^2)^2=x^4\Rightarrow x^4-x=0\Rightarrow x(x^3-1)=0\Rightarrow x=0\text{ or }x=1$.

At x=0: y=0^2=0 — critical point (0,0). At x=1: y=1^2=1 — critical point (1,1).

f_{xx}=6x,\qquad f_{yy}=6y,\qquad f_{xy}=-3

At (0,0): D=(0)(0)-(-3)^2=-9<0.

\boxed{(0,0)\text{ is a saddle point}}

At (1,1): D=(6)(6)-(-3)^2=36-9=27>0, and f_{xx}(1,1)=6>0.

\boxed{(1,1)\text{ is a local minimum}}

Sanity check. At (1,1): f(1,1)=1-3+1=-1. Nearby, e.g. (1.1,1): f=1.331-3.3+1=-0.969 — larger than -1, consistent with a local minimum. At (0,0): f(0,0)=0; moving along x=y (a diagonal through the saddle), f(t,t)=t^3-3t^2+t^3=2t^3-3t^2, which for small t>0 is negative (dominated by the -3t^2 term) while for small t<0 it's also negative — but checking y=-x instead: f(t,-t)=t^3+3t^2-t^3=3t^2>0 for any nonzero t. Different signs along different directions through the same point — the literal definition of a saddle, confirmed directly. ✓

Your turn

1. Find the critical points of f(x,y)=x^2+y^2-4x+6y+13 (a shifted paraboloid) and classify them.

2. Find the critical points of f(x,y)=y^2-x^2 and classify them.

3. True or false: if D>0 at a critical point, the second-derivative test alone determines whether it's a max or a min.

Solutions

1. f_x=2x-4=0\Rightarrow x=2. f_y=2y+6=0\Rightarrow y=-3. One critical point: (2,-3).

f_{xx}=2,\qquad f_{yy}=2,\qquad f_{xy}=0

D=(2)(2)-0^2=4>0,\qquad f_{xx}=2>0

\boxed{(2,-3)\text{ is a local minimum}}

2. f_x=-2x=0\Rightarrow x=0. f_y=2y=0\Rightarrow y=0. One critical point: (0,0).

f_{xx}=-2,\qquad f_{yy}=2,\qquad f_{xy}=0

D=(-2)(2)-0^2=-4<0

\boxed{(0,0)\text{ is a saddle point}}

(This is the same saddle shape as f(x,y)=x^2-y^2 from the concept section, just with the roles of x and y swapped — increasing along y, decreasing along x.)

3. True. Once D>0 is confirmed, f_{xx} and f_{yy} are guaranteed to share the same sign (as the concept section explained — if they disagreed, their product would be negative, forcing D<0). Checking f_{xx}'s sign alone is therefore sufficient: positive means both second partials are positive (curving upward in every direction, a minimum), negative means both are negative (a maximum) — no ambiguity remains once D>0 is established.

Check yourself in code

Find and classify the real critical points of f(x,y)=x^3-3xy+y^3.

Print exactly this:

(0, 0): D=-9, f_xx=0  ->  saddle point
(1, 1): D=27, f_xx=6  ->  local minimum
import sympy as sp

x, y = sp.symbols('x y')
f = x**3 - 3*x*y + y**3

f_x = sp.diff(f, x)
f_y = sp.diff(f, y)
critical_points = sp.solve([f_x, f_y], [x, y])

f_xx = sp.diff(f, x, 2)
f_yy = sp.diff(f, y, 2)
f_xy = sp.diff(f_x, y)

for pt in critical_points:
    if not all(v.is_real for v in pt):
        continue
    subs = {x: pt[0], y: pt[1]}
    D = f_xx.subs(subs) * f_yy.subs(subs) - f_xy.subs(subs)**2
    fxx_val = f_xx.subs(subs)
    if D > 0 and fxx_val > 0:
        kind = "local minimum"
    elif D > 0 and fxx_val < 0:
        kind = "local maximum"
    elif D < 0:
        kind = "saddle point"
    else:
        kind = "inconclusive"
    print(f"{pt}: D={D}, f_xx={fxx_val}  ->  {kind}")
import sympy as sp

x, y = sp.symbols('x y')
f = x**3 - 3*x*y + y**3

f_x = sp.diff(f, x)
f_y = sp.diff(f, y)
critical_points = sp.solve([f_x, f_y], [x, y])

f_xx = sp.diff(f, x, 2)
f_yy = sp.diff(f, y, 2)
f_xy = sp.diff(f_x, y)

for pt in critical_points:
    if not all(v.is_real for v in pt):
        continue
    subs = {x: pt[0], y: pt[1]}
    D = f_xx.subs(subs) * f_yy.subs(subs) - f_xy.subs(subs)**2
    fxx_val = f_xx.subs(subs)
    if D > 0 and fxx_val > 0:
        kind = "local minimum"
    elif D > 0 and fxx_val < 0:
        kind = "local maximum"
    elif D < 0:
        kind = "saddle point"
    else:
        kind = "inconclusive"
    print(f"{pt}: D={D}, f_xx={fxx_val}  ->  {kind}")

Every local extremum sits at a critical point (\nabla f=\vec0), exactly as in §3.5, but two variables introduce a genuinely new possibility — the saddle point, where curvature disagrees across different directions through the same point. The discriminant D=f_{xx}f_{yy}-(f_{xy})^2 detects that disagreement directly: D<0 means a saddle, and once D>0 guarantees consistent curvature everywhere, the sign of f_{xx} alone recovers §3.5's original max-versus-min rule.

Next: finding extrema not over the whole plane, but restricted to a curve — where Lagrange multipliers turn a constrained optimization problem into an unconstrained one about parallel gradients.