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
You want to penalize deviation from a target — |x - target| — but
absolute value isn’t linear.
When to use it
Whenever the absolute value appears in the objective being minimized,
or in a constraint of the form |x| <= b. This is one of the few
linearization tricks that needs zero extra binary variables.
Formulation
Split x into a positive and negative deviation part:
x = x_pos - x_neg
x_pos >= 0
x_neg >= 0
|x| is replaced by (x_pos + x_neg) in the objective
Minimizing x_pos + x_neg in the objective is enough — the solver will
never pay for both simultaneously, so at the optimum one of them is always
zero and x_pos + x_neg naturally equals |x|.
Code sketch
import pulp
prob = pulp.LpProblem("min_deviation", pulp.LpMinimize)
x_pos = pulp.LpVariable("x_pos", lowBound=0)
x_neg = pulp.LpVariable("x_neg", lowBound=0)
target = 50
# original variable, reconstructed
x = pulp.LpVariable("x")
prob += x == target + x_pos - x_neg
prob += x_pos + x_neg # objective: minimize |x - target|
Pitfalls
- This only works cleanly when you’re minimizing the deviation term (or
bounding it above). If you’re maximizing
|x|, the solver has an incentive to inflate bothx_posandx_neg— you’ll need binaries or an indicator constraint to force complementarity instead. - Don’t forget the reconstruction constraint (
x == target + x_pos - x_neg) — it’s easy to drop and end up with an under-constrained model.