Mathematical programming / Linearization

Piecewise Linear Approximation

Approximate a nonlinear cost or production curve with connected line segments so a linear/MILP solver can still optimize over it.

Note Advanced

Short note. A compact reference, correct as far as it goes. It will be expanded into a full guide with a worked example and an interactive demonstration.

Problem

Real cost curves are rarely straight lines — bulk discounts, economies of scale, and diminishing returns all bend. But MILP solvers want linear (or at worst convex quadratic) terms.

When to use it

Any nonlinear function of a single variable that you’re willing to approximate with straight segments: production cost curves, fuel consumption vs. speed, warehouse cost vs. utilization.

Formulation

Break the domain of x into breakpoints x_0 < x_1 < ... < x_k with known function values f(x_i). Using the SOS2 (special-ordered-set) formulation, introduce weights w_i >= 0 such that at most two adjacent weights are nonzero:

x  = sum(w_i * x_i for i in breakpoints)
f  = sum(w_i * f(x_i) for i in breakpoints)
sum(w_i) = 1
at most 2 consecutive w_i nonzero   # SOS2 constraint

Code sketch

import gurobipy as gp

model = gp.Model()
x = model.addVar(name="x")
f = model.addVar(name="f")

breakpoints = [0, 100, 300, 600, 1000]
values = [0, 800, 1900, 3000, 3800]  # f(x) at each breakpoint

model.addGenConstrPWL(x, f, breakpoints, values)

Most commercial solvers (Gurobi’s addGenConstrPWL, CPLEX’s piecewise helpers) wrap the SOS2 machinery for you — reach for those before hand-rolling weights.

Pitfalls

  • More breakpoints = better accuracy but more binary/SOS overhead and a slower solve. Start coarse, add breakpoints only where curvature is sharp.
  • If the curve is convex and you’re minimizing cost (or concave and maximizing), you often don’t need SOS2 at all — a simple set of linear segments taken as an upper envelope works because the LP will naturally pick the right one. Try that first; it’s much cheaper.
  • Approximation error compounds if this variable feeds into other nonlinear relationships downstream.