Numerical Function Minimization via Gradient Descent

Optimization · Medium · Free problem

Implement gradient descent to minimize a polynomial given by its coefficient list.

Write a function with signature:

```python def gd_minimize(coeffs, x0, lr, max_iter): ```

where f(x) = sum(coeffs[i] * xi) (so coeffs = [10, -6, 1] means $f(x) = 10 - 6x + x^2$). You do NOT have an analytic derivative — approximate $f'(x)$ with a central difference**. Follow this pinned deterministic protocol so the result is reproducible:

  • finite-difference step $h = 10^{-5}$
  • convergence tolerance $\text{tol} = 10^{-10}$ on $|x_{new} - x|$
  • update $x \leftarrow x - \text{lr} \cdot f'(x)$; stop when $|x_{new} - x| < \text{tol}$ or max_iter is reached
  • start at $x = x_0$

Return the final $x$ (the approximate argmin) as a float — do not print it.

Constraints: - $f$ is a scalar polynomial $\mathbb{R} \to \mathbb{R}$ described by coeffs - $f$ has at least one local minimum reachable from $x_0$ - No analytic derivative is available

Example

gd_minimize([10.0, -6.0, 1.0], 0.0, 0.2, 50000) -> 2.9999999999308358

Here $f(x) = x^2 - 6x + 10 = (x-3)^2 + 1$, whose minimum is at $x = 3$; gradient descent from $x_0 = 0$ converges to essentially $3$ (up to the finite-difference/tolerance protocol).

Hints

  1. Start with the simplest version: fixed step size, central difference for the gradient. Get the basic loop working before adding enhancements.
  2. The central difference $\frac{f(x+h) - f(x-h)}{2h}$ has error $O(h^2)$ vs. $O(h)$ for forward difference. The optimal $h$ balances truncation error against floating-point roundoff.
  3. For faster convergence, approximate $f''(x) \approx \frac{f(x+h) - 2f(x) + f(x-h)}{h^2}$ and use Newton's step $x \leftarrow x - f'(x)/f''(x)$.

Worked Solution

How to Think About It: Gradient descent repeatedly steps in the direction that decreases $f$. Here $f$ is a polynomial given by its coefficient list, coeffs, so $f(x) = \sum_i \text{coeffs}[i]\, x^i$. We do NOT get an analytic derivative, so we approximate $f'(x)$ from function evaluations. This problem pins a fully deterministic protocol so the answer is reproducible: central difference with finite-difference step $h = 10^{-5}$, convergence tolerance $\text{tol} = 10^{-10}$ on $|x_{new} - x|$, update rule $x \leftarrow x - \text{lr} \cdot f'(x)$, starting at $x_0$, stopping when $|x_{new} - x| < \text{tol}$ or max_iter is reached. The function returns the final $x$ (the approximate argmin).

Algorithm:

  1. Build $f(x) = \sum_i \text{coeffs}[i]\, x^i$ from the coefficient list.
  2. At each step approximate $f'(x) \approx \dfrac{f(x+h) - f(x-h)}{2h}$ (central difference, $O(h^2)$ accurate).
  3. Update $x \leftarrow x - \text{lr} \cdot f'(x)$.
  4. Stop when $|x_{new} - x| < \text{tol}$ or max_iter iterations elapse; return the final $x$.

Code:

```python def gd_minimize(coeffs, x0, lr, max_iter): # Minimize f(x) = sum(coeffs[i] * x**i) by gradient descent, approximating # f'(x) with a CENTRAL difference. Pinned deterministic protocol: # h = 1e-5, tol = 1e-10, update x <- x - lr * f'(x), # stop when |x_new - x| < tol OR max_iter reached. Start at x0. h = 1e-5 tol = 1e-10

def f(x): total = 0.0 for i, c in enumerate(coeffs): total += c * x**i return total

x = x0 for _ in range(max_iter): grad = (f(x + h) - f(x - h)) / (2 * h) x_new = x - lr * grad if abs(x_new - x) < tol: x = x_new break x = x_new return x ```

Why central difference: The forward difference $\frac{f(x+h)-f(x)}{h}$ is $O(h)$ accurate and costs one extra evaluation, while the central difference $\frac{f(x+h)-f(x-h)}{2h}$ is $O(h^2)$ accurate at two evaluations — the first-order error term cancels by symmetry. The optimal $h$ balances truncation error against floating-point roundoff, giving $h^\star \approx \epsilon^{1/3} \approx 10^{-5}$, which is exactly the pinned value.

Enhancements that improve convergence:

  1. Adaptive step size (backtracking line search): instead of a fixed lr, shrink the step until the Armijo sufficient-decrease condition $f(x - \alpha g) \le f(x) - c\,\alpha g^2$ holds.
  2. Newton's method: use the numerical second derivative $f''(x) \approx \frac{f(x+h) - 2f(x) + f(x-h)}{h^2}$ and step $x \leftarrow x - f'(x)/f''(x)$ for quadratic convergence near the minimum (at the risk of diverging when $f''$ is small or negative).
  3. Momentum: accumulate a running average of past gradients to damp oscillations in narrow valleys.

Note: the function signature is gd_minimize(coeffs, x0, lr, max_iter) and it must return the final $x$ (a float), not print it.

Intuition

Gradient descent is conceptually simple -- walk downhill -- but the practical details matter. The finite difference step $h$ is a Goldilocks problem: too large and the derivative approximation is inaccurate (truncation error), too small and floating-point arithmetic kills you (cancellation error). For central differences, the sweet spot is around $h \sim 10^{-5}$.

The deeper lesson is about the hierarchy of optimization methods. Gradient descent uses only first-order information (the slope) and converges linearly. Newton's method uses second-order information (the curvature) and converges quadratically, but it can misbehave when the curvature is wrong (non-convex regions). In quant work, you encounter this tradeoff constantly -- calibrating option pricing models, fitting yield curves, or optimizing portfolio weights. The choice between methods depends on the cost of function evaluations, the smoothness of the objective, and how close you need to get to the true optimum.

Open the full interactive solver →