The theory of optimisation collides with practice at the solver. Choosing the right solver, formulating the problem in a way the solver can digest, diagnosing infeasibility, and validating the answer are the skills that turn a textbook problem statement into a number you put on a trade ticket.
The modelling layer — cvxpy
cvxpy (Python) and JuMP (Julia) are domain-specific languages for disciplined convex programming. Write the problem in math-like syntax; the library compiles it into the canonical form expected by underlying solvers (ECOS, SCS, MOSEK, GUROBI). This abstraction eliminates the bug class where you 'thought' a problem was convex but the solver couldn't tell.
import cvxpy as cpimport numpy as npn = len(mu)w = cp.Variable(n)risk = cp.quad_form(w, Sigma)ret = mu @ wobjective = cp.Minimize(0.5 * risk - lam * ret)constraints = [cp.sum(w) == 1, w >= 0]prob = cp.Problem(objective, constraints)prob.solve(solver=cp.OSQP)
Choosing a solver
- LP: GLPK (free), HiGHS (free), Gurobi, CPLEX, MOSEK (commercial).
- QP: OSQP (free, ADMM-based), Gurobi, MOSEK.
- SOCP / SDP: ECOS, SCS (free), MOSEK (commercial, best-in-class).
- MILP / MIQP: SCIP, HiGHS, Gurobi, CPLEX (commercial dominate for hard MIPs).
- General non-linear: IPOPT (interior point), Knitro.
Warm-starting
Solving a sequence of similar problems (rolling-horizon optimisation, efficient-frontier sweep) is much faster if each new solve starts from the previous solution. OSQP, ECOS, Gurobi, and MOSEK all support warm-starting; cvxpy's warm_start=True flag forwards primal/dual variables between solves.
Pre-flight checklist
- Is the problem convex? Run cp.Problem.is_dcp() — cvxpy's DCP check.
- Are constraints feasible? Try minimising 0 subject to constraints; if infeasible, problem reports infeasible.
- Are inputs sane? Check that Σ is PSD (eigvals ≥ 0), μ has no NaNs/infs, return targets are achievable.
- Is the solution unique? Strict convexity + strict feasibility imply uniqueness; for QPs, PD P ensures unique x*.
- Are dual variables sane? Lagrange multipliers should be non-negative on inequality constraints, finite, and report shadow prices that make economic sense.
Diagnosing infeasibility
Solver reports status 'infeasible' — what now? Strategies:
- Relax inequality constraints one at a time; identify the binding offender.
- Solve the elastic-mode reformulation: replace each constraint g ≤ b with g - b ≤ s, s ≥ 0; minimise Σ s. Constraints whose s > 0 in the relaxed solution are the infeasible ones.
- Check the dimensionality: is your constraint matrix accidentally rank-deficient with conflicting rows?
Numerical scaling
Solvers are happiest when the variables and constants are all in the unit range. A portfolio with weights in [-1, 1], returns in [-0.5, 0.5], variances around 0.01 — fine. A portfolio whose objective combines variance (10⁻⁴) and dollar P&L (10⁹) — solver will struggle. Pre-scale objectives and constraints to unit-order before passing to the solver.
Validation
Never trust a solver's answer without independent checks:
- Re-evaluate the objective at the reported solution.
- Check constraint residuals are within tolerance.
- Spot-check edge cases (zero-weight assets, binding constraints, etc.).
- Run a second solver on the same problem — agreement is strong evidence of correctness.
- Stress-test by perturbing inputs slightly and confirming the solution moves smoothly.
Production patterns
- Caching: results of identical inputs should be cached.
- Logging: capture inputs, solver status, runtime, KKT residuals.
- Fallbacks: if MOSEK fails, retry with ECOS or relaxed tolerance.
- Regression tests: maintain a corpus of known problems and their expected solutions; run on every code change.
- Sensitivities: compute and display ∂x*/∂μ, ∂x*/∂Σ; let users see how an input change moves the answer.
Exercise
A portfolio optimisation in production starts returning 'solver infeasible' on Monday morning. The same code worked Friday. What's your diagnostic playbook?