Exercises — scipy.optimize — minimize, fsolve, curve_fit, linprog
The four engines in one glance
Before we start, a picture of what problem each tool solves. Look at each panel: the little dot is the answer the tool hunts for.

Level 1 — Recognition
L1·Q1 — Which tool?
For each task, name the single best scipy.optimize function.
(a) Find the smallest value of . (b) Find every where . (c) Choose so hugs 200 noisy sensor readings. (d) Maximize subject to , .
Recall Solution
(a) minimize — we want the smallest value of a scalar objective. (b) fsolve — rewrite as ; we want a root. (c) curve_fit — we are fitting a model to data (least squares). (d) linprog — linear objective, linear constraints ⇒ the answer lives at a corner.
The tell-tale words: smallest → minimize, equals zero / solve → fsolve, fit data → curve_fit, linear + constraints → linprog.
L1·Q2 — Read the result object
After res = minimize(f, x0), which attribute holds the winning input, which holds the winning score, and which is the True/False flag that it worked?
Recall Solution
res.x::: the solution vector (the winning input).res.fun::: the objective value (the winning score).res.success::: boolean flag —Trueif the solver believes it converged.
Level 2 — Application
L2·Q1 — Minimize a 1D quartic
Minimize starting from x0=2. What is and ?
Recall Solution
WHAT: we look for a stationary point where the slope .
WHY those: setting the derivative to zero finds flat spots — candidates for minima. is a local max (a hilltop), and are the two valleys.
Starting at x0=2 (right side), the iteration rolls down into the right valley .
from scipy.optimize import minimize
f = lambda x: x[0]**4 - 3*x[0]**2 + 2
res = minimize(f, x0=[2.0])
print(res.x) # ≈ [1.2247]
print(res.fun) # ≈ -0.25Answer: , .
L2·Q2 — fsolve a nonlinear pair
Solve and from x0=[1,1].
Recall Solution
WHY move to one side: fsolve seeks where the returned vector is , so rewrite each equation as something = 0.
from scipy.optimize import fsolve
def F(v):
x, y = v
return [x**2 + y**2 - 25, x - y - 1]
print(fsolve(F, x0=[1,1])) # ≈ [4., 3.]By hand: , so . Roots (giving ) or (giving ). The seed [1,1] is nearer the first root.
Answer: .
L2·Q3 — linprog a tiny plan
Maximize with , , .
Recall Solution
WHY negate: linprog only minimizes, so to maximize we minimize .
from scipy.optimize import linprog
c = [-5, -4]
A_ub = [[6,4],[1,2]]
b_ub = [24, 6]
res = linprog(c, A_ub=A_ub, b_ub=b_ub, bounds=[(0,None),(0,None)])
print(res.x) # ≈ [3., 1.5]
print(-res.fun) # 21.0Corner-hunting by hand: the two active constraints intersect where and . Multiply the second by 2: . Subtract from the first: , then . Objective . Answer: , profit .
Level 3 — Analysis
L3·Q1 — One Newton step by hand
fsolve is built on Newton's method: . For starting at , compute and by hand. What are they converging to?
Recall Solution
WHAT Newton does: it replaces the curve by its tangent line at and jumps to where that line crosses zero — a picture worth holding in mind. . It is racing toward . Notice how fast: already matches to three decimals. That doubling of correct digits per step is Newton's signature. See Newton's Method. Answer: , , converging to .
L3·Q2 — Why the seed decides the root
For the system in L2·Q2, predict which root fsolve returns from x0=[-5,-5], and explain geometrically.

Recall Solution
WHY the seed matters: Newton-type solvers are local — they follow the tangent downhill from the seed and lock onto the nearest root, never scanning globally.
The circle meets the line at two points: (upper-right) and (lower-left). The seed sits in the lower-left, closest to .
Answer: fsolve returns . Look at the figure: each seed's basin of attraction is the side of the line it starts on.
L3·Q3 — Least-squares line by the normal equations
Fit to the three points . Minimize analytically. Give .
Recall Solution
WHY set derivatives to zero: is a smooth bowl in ; its lowest point has both partial slopes zero. and give the normal equations: Numbers: , , , , . Subtract: ; then . This is exactly what Least Squares Regression and NumPy polyfit compute in closed form — no iteration needed because the model is linear. Answer: , .
Level 4 — Synthesis
L4·Q1 — Same problem, two tools
Find the minimum of twice: once with minimize, once by handing to fsolve. Show both give the same .
Recall Solution
The unifying idea: minimizing = finding a root of . Two APIs, one skeleton. . Root of is ; that is also the valley bottom, where .
from scipy.optimize import minimize, fsolve
f = lambda x: (x[0]-4)**2 + 1
df = lambda x: [2*(x[0]-4)]
print(minimize(f, x0=[0]).x) # ≈ [4.]
print(fsolve(df, x0=[0])) # ≈ [4.]Answer: both return ; . The Hessian confirms it is a minimum (see Gradient and Hessian).
L4·Q2 — Constrained by hand, checked by linprog
A bakery makes cakes () and pies (), profit \3$2x_1+x_2\le 1002x_1+x_2\le 150\ge 0$. Find the best mix and profit.
Recall Solution
WHY corners: a linear objective never flattens inside the region — its gradient is constant — so you slide along the walls to a vertex (see Linear Programming Simplex, Convex Optimization). Candidate corners of the feasible polygon:
- : profit .
- (oven wall, ): profit .
- (flour wall, ): profit .
- Intersection of oven & flour: , . Subtract ⇒ , . Profit . The intersection corner wins.
from scipy.optimize import linprog
res = linprog([-3,-2], A_ub=[[1,1],[2,1]], b_ub=[100,150],
bounds=[(0,None),(0,None)])
print(res.x) # ≈ [50., 50.]
print(-res.fun) # 250.0Answer: 50 cakes, 50 pies, profit \250$.
Level 5 — Mastery
L5·Q1 — Exponential fit, error bars
You fit with curve_fit and get pcov = [[0.0016, 0], [0, 0.0009]]. Report the uncertainty on and . What does a large off-diagonal entry mean?
Recall Solution
WHY the square root: pcov is the covariance matrix; its diagonal holds variances . The uncertainty (standard deviation) is the square root.
import numpy as np
pcov = [[0.0016,0],[0,0.0009]]
print(np.sqrt(np.diag(pcov))) # [0.04 0.03]A large off-diagonal entry means and are correlated — the fit can't pin them down independently (raising while lowering gives a similar curve). Here the off-diagonals are , so they are independent. Answer: , .
L5·Q2 — Where Newton stalls
Explain what happens when fsolve (Newton at heart) tries from . Compute two steps and describe the failure/slowdown.
Recall Solution
The subtlety: is a double root ( and both vanish there). Newton's fast doubling of digits assumes a simple root; at a double root it crawls, roughly halving the error each step (linear, not quadratic).
. Update .
It keeps halving toward — it does converge, but slowly, and fsolve may report near-success with a residual that shrinks lazily.
Answer: , ; convergence is merely linear (halving) because of the double root.
L5·Q3 — Diagnose a bad fit
Someone runs curve_fit(model, x, y) on a nonlinear model with no p0, and gets nonsense (or a RuntimeError). State the cause and the one-line fix.
Recall Solution
Cause: with no p0, curve_fit defaults every parameter to . Nonlinear least squares is non-convex — the error surface has many valleys — so a poor seed can slide into a wrong valley or fail to converge.
Contrast: linear fits like NumPy polyfit need no seed because their error surface is a single bowl (convex), solvable in closed form.
Fix: supply a physically sensible seed, e.g. curve_fit(model, x, y, p0=[y.max(), 1.0]).
Answer: default seed + non-convex surface → divergence; fix with a good p0.
Recall Feynman recap: the whole ladder in one breath
You learned to spot the right engine (L1), drive each one (L2), see why Newton and least-squares work the way they do (L3), bridge two tools on one problem (L4), and diagnose the quiet failure modes — double roots, missing seeds, deceptive residuals (L5). One skeleton underneath it all: guess, look at the local shape, step toward better, repeat.