1.022 Python Optimization Libraries#
Explainer
Mathematical Optimization: Business Introduction#
What is Mathematical Optimization?#
Mathematical optimization (also called mathematical programming) is the process of finding the best solution from a set of possible choices, subject to constraints. Unlike simulation that explores “what if” scenarios, or heuristics that provide reasonable solutions, optimization mathematically guarantees the best achievable outcome given your objectives and limitations.
Why Use Mathematical Optimization?#
When Traditional Approaches Fall Short#
Many business problems involve making decisions with:
- Multiple competing objectives: Minimize cost while maximizing quality
- Complex constraints: Limited resources, capacity restrictions, regulatory requirements
- Combinatorial complexity: Thousands or millions of possible solutions to evaluate
For these problems, trial-and-error or even sophisticated heuristics may miss the optimal solution entirely. Mathematical optimization systematically searches the solution space to find provably optimal answers.
Core Concepts#
Objective Function#
What you want to optimize:
- Minimize: Costs, time, risk, waste, energy consumption
- Maximize: Revenue, throughput, efficiency, customer satisfaction
Decision Variables#
What you can control:
- Quantities to produce
- Resources to allocate
- Schedules to set
- Routes to follow
Constraints#
What limits your options:
- Budget limitations
- Capacity restrictions
- Time windows
- Physical limitations
- Regulatory requirements
- Business rules
When to Use Each Approach#
Mathematical Optimization#
Best for: Problems with clear objectives, well-defined constraints, and where you need the provably best solution.
Examples:
- Resource allocation across projects with budget constraints
- Production planning to minimize cost while meeting demand
- Portfolio optimization balancing risk and return
- Workforce scheduling with labor rules and coverage requirements
- Supply chain network design minimizing total cost
Advantages:
- Guarantees optimality (for solvable problem types)
- Handles complex constraint interactions automatically
- Provides sensitivity analysis (what happens if constraints change?)
- Scales to large problems with modern solvers
Limitations:
- Requires mathematically expressible objectives and constraints
- Some problem types (nonlinear, non-convex) are computationally hard
- May not capture all real-world complexities
Heuristics & Rules-Based Approaches#
Best for: Problems where optimization is too slow, or where simple rules capture sufficient domain knowledge.
Examples:
- First-come-first-served scheduling
- Greedy allocation algorithms
- Priority-based dispatching
Advantages:
- Fast to compute
- Easy to explain to stakeholders
- Can incorporate hard-to-quantify expertise
Limitations:
- No guarantee of quality
- May be far from optimal
- Difficult to handle constraint interactions
Simulation#
Best for: Understanding system behavior, quantifying uncertainty, or when the system is too complex to optimize directly.
Examples:
- Modeling customer flow through a service center
- Evaluating risk across uncertain scenarios
- Testing what-if scenarios
Advantages:
- Models complex, stochastic systems
- Evaluates variability and risk
- No need for closed-form equations
Limitations:
- Doesn’t find optimal decisions (only evaluates given scenarios)
- Can be computationally expensive
- Requires many simulation runs for statistical significance
Simulation + Optimization#
Best for: Complex systems where the objective can’t be written analytically, but can be evaluated through simulation.
Examples:
- Optimizing inventory policies in a supply chain with complex lead times
- Finding best control parameters for a manufacturing process
- Tuning staffing levels in a service system
Approach: Use simulation to evaluate objective function, use optimization to search for best parameters.
Generic Business Value#
Mathematical optimization delivers value across industries:
Cost Reduction#
- Minimize production costs while meeting demand
- Reduce transportation and logistics expenses
- Optimize energy consumption
- Minimize inventory holding costs
Revenue Maximization#
- Optimal pricing strategies
- Product mix optimization
- Capacity allocation to high-value customers
- Resource allocation to high-return opportunities
Resource Efficiency#
- Maximize throughput from limited resources
- Optimal workforce scheduling and assignment
- Equipment utilization optimization
- Space utilization in facilities
Service Quality#
- Minimize customer wait times
- Balance workload across resources
- Meet service level agreements with minimal cost
- Optimize coverage and availability
Risk Management#
- Portfolio diversification
- Robust solutions under uncertainty
- Minimize worst-case scenarios
- Balance risk and return
Generic Examples Across Industries#
Resource Allocation#
Problem: Allocate limited budget across N projects to maximize total return, where projects have different costs and returns, and some projects have dependencies.
Optimization approach: Mixed-integer programming to select project portfolio maximizing total value subject to budget and dependency constraints.
Scheduling with Precedence#
Problem: Schedule tasks with precedence constraints (some tasks must finish before others can start) to minimize total completion time.
Optimization approach: Constraint programming or mixed-integer programming with precedence and resource capacity constraints.
Portfolio Optimization#
Problem: Select mix of assets that maximizes expected return while keeping risk below a threshold, with constraints on diversification.
Optimization approach: Quadratic programming (minimize variance of portfolio return) or robust optimization (worst-case scenarios).
Network Flow Optimization#
Problem: Route flow through a network (supply chain, communication network, transportation) to minimize cost while satisfying demand at destinations.
Optimization approach: Linear programming (network flow problems have special structure enabling efficient solution).
Cutting Stock / Bin Packing#
Problem: Cut raw materials into required pieces minimizing waste, or pack items into containers minimizing number of containers used.
Optimization approach: Mixed-integer programming with complex cutting patterns or packing configurations.
Modern Tooling Landscape#
Python has become the dominant platform for optimization due to:
- Rich ecosystem: Multiple modeling languages and solver interfaces
- Integration: Easy connection to data pipelines, machine learning, simulation
- Accessibility: Free, open-source tools competitive with commercial software
- Flexibility: From rapid prototyping to production deployment
The optimization landscape spans:
- Open-source solvers: Free, high-quality solvers (HiGHS, SCIP, IPOPT)
- Algebraic modeling: Express models in mathematical notation (Pyomo, CVXPY, PuLP)
- Commercial solvers: Premium performance for large-scale problems (Gurobi, CPLEX)
- Specialized libraries: Multi-objective optimization, dynamic optimization, constraint programming
Getting Started#
- Identify your problem type: Linear? Integer variables? Nonlinear? Convex?
- Start simple: Begin with small models, validate results
- Iterate: Add complexity gradually, test constraint impacts
- Validate: Compare optimization results to current practice or heuristics
- Sensitivity analysis: Understand how solution changes with parameters
Mathematical optimization is a powerful tool when applied to well-defined problems. The key is understanding when optimization is the right approach, what problem type you’re solving, and selecting appropriate tools for your use case.
S1: Rapid Discovery
Rapid Discovery: What is Mathematical Optimization?#
Technical Overview#
Mathematical optimization (mathematical programming) is the discipline of finding the best element from a feasible set with respect to an objective criterion. Formally:
minimize (or maximize) f(x)
subject to g_i(x) ≤ 0, i = 1,...,m
h_j(x) = 0, j = 1,...,p
x ∈ XWhere:
- f(x): Objective function to minimize/maximize
- x: Decision variables (what we control)
- g_i(x): Inequality constraints
- h_j(x): Equality constraints
- X: Domain of variables (e.g., real numbers, integers)
Problem Type Taxonomy#
The structure of f(x), g_i(x), h_j(x), and X determines problem type, which drives solver selection.
Linear Programming (LP)#
Definition: Linear objective, linear constraints, continuous variables.
minimize c^T x
subject to Ax ≤ b
x ≥ 0Example: Maximize profit from production of multiple products with resource constraints.
Characteristics:
- Polynomial-time solvable (simplex, interior point methods)
- Global optimum guaranteed
- Well-understood theory
- Efficient solvers (HiGHS, GLPK, commercial)
When to use: Resource allocation, blending problems, network flows, diet problems, transportation problems.
Mixed-Integer Linear Programming (MILP/MIP)#
Definition: LP where some/all variables must be integers.
minimize c^T x
subject to Ax ≤ b
x_i ∈ {0,1} or x_i ∈ ℤ for some iExample: Select which facilities to open (binary decisions) to minimize total cost.
Characteristics:
- NP-hard (computationally difficult)
- Branch-and-bound, branch-and-cut algorithms
- Modern solvers extremely effective for practical instances
- Special structure (e.g., network flows) helps
When to use: Yes/no decisions (selection, assignment), scheduling with discrete time periods, facility location, cutting stock, bin packing.
Quadratic Programming (QP)#
Definition: Quadratic objective, linear constraints.
minimize (1/2) x^T Q x + c^T x
subject to Ax ≤ bExample: Portfolio optimization minimizing variance (quadratic) subject to return requirements.
Characteristics:
- If Q is positive semidefinite (convex), efficiently solvable
- If Q is indefinite (non-convex), NP-hard
- Interior point methods effective for convex case
When to use: Portfolio optimization, least-squares problems, model predictive control.
Nonlinear Programming (NLP)#
Definition: Nonlinear objective or constraints.
minimize f(x)
subject to g_i(x) ≤ 0Example: Minimize chemical reactor cost (nonlinear engineering equations) subject to safety constraints.
Characteristics:
- Wide range of difficulty depending on problem structure
- Local optimum vs global optimum distinction critical
- Gradient-based methods (BFGS, SQP, interior point)
- Derivative-free methods for non-smooth functions
When to use: Engineering design, parameter estimation, fitting nonlinear models, physical system optimization.
Convex Optimization#
Definition: Convex objective function, convex feasible region.
A function f is convex if:
f(αx + (1-α)y) ≤ αf(x) + (1-α)f(y) for all α ∈ [0,1]Example: Minimize convex loss function subject to norm constraints.
Characteristics:
- Any local optimum is global optimum
- Polynomial-time solvable for many subclasses
- LP and convex QP are special cases
- Includes conic programming (SOCP, SDP)
When to use: Machine learning (SVM, logistic regression), signal processing, control systems, robust optimization.
Constraint Programming (CP)#
Definition: Logical and combinatorial constraints, often with discrete variables.
Example: Scheduling tasks with precedence constraints, resource limits, and no-overlap requirements.
Characteristics:
- Domain propagation and constraint inference
- Effective for scheduling, timetabling, configuration
- Different paradigm from mathematical programming
When to use: Scheduling with complex logical rules, rostering, configuration problems, puzzles.
Multi-Objective Optimization#
Definition: Multiple objective functions simultaneously.
minimize [f_1(x), f_2(x), ..., f_k(x)]
subject to g_i(x) ≤ 0Example: Minimize cost AND minimize emissions (competing objectives).
Characteristics:
- No single “optimal” solution
- Find Pareto frontier (solutions where improving one objective worsens another)
- Requires preference specification or generate full frontier
When to use: Trade-off analysis, multi-criteria decision making, design optimization with competing goals.
Solver vs Modeling Language Distinction#
Solver#
The engine that implements optimization algorithms and computes solutions.
Examples:
- Open-source: HiGHS, CBC, GLPK, SCIP, IPOPT, OSQP
- Commercial: Gurobi, CPLEX, MOSEK, XPRESS
Role: Takes problem in standard form (MPS, LP file, or direct API) and returns solution.
Modeling Language#
The interface for expressing optimization problems in human-readable form.
Examples:
- Python: Pyomo, CVXPY, PuLP, OR-Tools
- Others: AMPL, GAMS, JuMP (Julia)
Role: Translates user model to solver input format, manages data, retrieves results.
Analogy: Modeling language is like SQL (express what you want), solver is like database engine (compute the result).
Optimization Algorithm Approaches#
Gradient-Based Methods#
Principle: Use derivatives to determine descent direction.
Algorithms:
- Gradient descent: Move in direction of negative gradient
- Newton’s method: Use second derivatives (Hessian) for faster convergence
- Quasi-Newton (BFGS): Approximate Hessian efficiently
- Sequential Quadratic Programming (SQP): Solve sequence of QP subproblems
- Interior point methods: Move through interior of feasible region
Requirements: Objective and constraints must be differentiable.
Advantages:
- Fast convergence for smooth problems
- Efficient for large-scale problems
- Mature theory and implementations
Limitations:
- May converge to local optima (non-convex problems)
- Requires gradient computation (analytical or automatic differentiation)
When to use: Continuous optimization, smooth functions, large scale.
Derivative-Free Methods#
Principle: Optimize without computing gradients.
Algorithms:
- Nelder-Mead simplex: Geometric search using simplex shape
- Powell’s method: Sequential line searches
- Pattern search: Evaluate on geometric patterns
- Trust region methods: Sample within trusted radius
Advantages:
- Handle non-smooth, noisy objectives
- Simple to implement
- No derivative computation needed
Limitations:
- Slower convergence than gradient-based
- Struggle with high dimensions
- No guarantee of global optimum
When to use: Black-box objectives (simulation-based), non-smooth functions, small to medium dimension.
Combinatorial/Discrete Optimization#
Principle: Systematically search discrete solution space.
Algorithms:
- Branch-and-bound: Partition space, bound subproblem solutions
- Branch-and-cut: Branch-and-bound with cutting planes
- Dynamic programming: Solve subproblems recursively
- Constraint propagation: Eliminate infeasible values
Characteristics:
- Exact methods guarantee optimal solution
- Computational complexity often exponential
- Modern implementations highly optimized
When to use: Integer variables, combinatorial structure.
Metaheuristics#
Principle: Heuristic search strategies inspired by natural processes.
Algorithms:
- Genetic algorithms: Evolutionary selection and crossover
- Simulated annealing: Probabilistic acceptance of worse solutions
- Particle swarm optimization: Population-based search
- Tabu search: Guided local search with memory
Advantages:
- Applicable to any problem type
- Can escape local optima
- Handle large, complex, black-box problems
Limitations:
- No optimality guarantee
- Many parameters to tune
- Computational cost (many evaluations)
When to use: Complex, non-convex problems where exact methods too slow, multi-objective optimization, robust optimization.
Key Insights for Solver Selection#
Problem type drives solver choice: LP solvers can’t handle integers, MILP solvers can’t handle nonlinearity. Know your problem type.
Convexity is gold: Convex problems have global optima and efficient algorithms. Test if your problem is convex.
Size matters differently: LP scales to millions of variables. MILP scales to thousands to hundreds of thousands. NLP scaling depends heavily on structure.
Modeling language adds convenience: For rapid development, algebraic modeling (Pyomo, CVXPY) beats direct API coding.
Commercial vs open-source gap narrowing: Open-source solvers (HiGHS, SCIP) competitive for many problems. Commercial edge on largest MILP instances.
Solver backend matters more than frontend: For production performance, solver (Gurobi vs CBC) dominates modeling language choice (Pyomo vs PuLP).
Problem Type Decision Tree#
Is objective and constraints linear?
├─ YES, all continuous → LP
│ └─ Solvers: HiGHS, GLPK, Gurobi, CPLEX
├─ YES, some integer → MILP
│ └─ Solvers: CBC, SCIP, HiGHS, Gurobi, CPLEX
└─ NO (nonlinear)
├─ Is problem convex?
│ ├─ YES → Convex optimization
│ │ └─ Solvers: ECOS, SCS, MOSEK, Clarabel
│ └─ NO → General NLP
│ └─ Solvers: IPOPT, SNOPT, Knitro
└─ Logical constraints, scheduling? → Constraint Programming
└─ Solvers: OR-Tools CP-SAT, Gecode
Multiple objectives?
└─ Multi-objective optimization (pymoo, weighted sum, epsilon-constraint)
Dynamic over time with differential equations?
└─ Dynamic optimization (GEKKO, Pyomo.DAE)Next Steps in S1-Rapid#
The following pages investigate specific Python libraries:
- scipy.optimize: Built-in Python scientific computing
- OR-Tools: Google’s operations research toolkit
- Pyomo: Algebraic modeling language
- CVXPY: Convex optimization specialist
- PuLP: Simple LP/MILP modeling
Each library page documents:
- Problem types supported
- Installation and basic example
- API approach and design philosophy
- Solver backends available
- Maturity and community indicators
- When to choose this library
CVXPY: Convex Optimization in Python#
Overview#
CVXPY is a Python-embedded modeling language for convex optimization problems. It provides automatic verification of problem convexity through Disciplined Convex Programming (DCP) analysis, ensuring that your problem can be solved globally and efficiently.
Key finding: CVXPY is the specialist for convex optimization, with Stanford academic origins and JMLR publication (2016). Unlike general-purpose tools, CVXPY verifies convexity at modeling time, preventing common errors.
Installation#
pip install cvxpyCVXPY includes open-source solvers (Clarabel, SCS, OSQP, ECOS) by default. Additional solvers (MOSEK, Gurobi, CPLEX) can be used if installed.
Problem Types Supported#
CVXPY is specialized for convex optimization:
| Problem Type | Supported | Notes |
|---|---|---|
| Linear Programming (LP) | ✅ Yes | Special case of convex |
| Quadratic Programming (QP) | ✅ Yes (if convex) | Positive semidefinite Q |
| Second-Order Cone (SOCP) | ✅ Yes | Norm constraints |
| Semidefinite Programming (SDP) | ✅ Yes | Matrix constraints |
| General Convex | ✅ Yes | If DCP-compliant |
| Mixed-Integer Convex | ⚠️ Limited | Via branch-and-bound (slow) |
| Nonconvex (general NLP) | ❌ No | Use scipy or Pyomo+IPOPT |
| Mixed-Integer LP (MILP) | ❌ No | Use PuLP, Pyomo, OR-Tools |
Core insight: If your problem is convex, CVXPY is likely the best choice. DCP analysis catches modeling errors early.
What is Convex Optimization?#
A problem is convex if:
- Objective function is convex (for minimization)
- Feasible region is convex
Why convexity matters:
- Any local optimum is a global optimum
- Polynomial-time algorithms available
- No initialization sensitivity
- Reliable, predictable solving
Common convex problems:
- Linear programming
- Least-squares regression
- Lasso, ridge regression
- Support vector machines (SVM)
- Portfolio optimization (mean-variance)
- Signal processing (filter design)
- Control systems (LQR, MPC)
Disciplined Convex Programming (DCP)#
DCP is a ruleset for constructing convex optimization problems. CVXPY automatically checks DCP compliance.
DCP rules:
- Convex functions can only be minimized or bounded above
- Concave functions can only be maximized or bounded below
- Affine functions can be used anywhere
- Composition rules ensure convexity is preserved
Example of DCP violation:
import cvxpy as cp
x = cp.Variable()
# ERROR: Cannot minimize a concave function
objective = cp.Minimize(-cp.sqrt(x)) # sqrt is concaveCVXPY raises an error immediately, preventing silent failures.
Basic Example: Linear Programming#
import cvxpy as cp
# Variables
x = cp.Variable()
y = cp.Variable()
# Objective: minimize -x - 2y (equivalent to maximize x + 2y)
objective = cp.Minimize(-x - 2*y)
# Constraints
constraints = [
2*x + y <= 20,
x + 2*y <= 20,
x >= 0,
y >= 0
]
# Create and solve problem
problem = cp.Problem(objective, constraints)
problem.solve(solver=cp.CLARABEL)
print(f"Status: {problem.status}")
print(f"Optimal value: {-problem.value}") # Negate for maximization
print(f"x = {x.value}")
print(f"y = {y.value}")Basic Example: Quadratic Programming (Portfolio Optimization)#
import cvxpy as cp
import numpy as np
# Portfolio optimization: minimize risk subject to return target
n_assets = 4
returns = np.array([0.10, 0.15, 0.12, 0.08]) # Expected returns
cov_matrix = np.array([ # Covariance matrix (risk)
[0.04, 0.01, 0.02, 0.01],
[0.01, 0.06, 0.01, 0.02],
[0.02, 0.01, 0.05, 0.01],
[0.01, 0.02, 0.01, 0.03]
])
# Variables: portfolio weights
w = cp.Variable(n_assets)
# Objective: minimize portfolio variance (risk)
risk = cp.quad_form(w, cov_matrix)
objective = cp.Minimize(risk)
# Constraints
constraints = [
cp.sum(w) == 1, # Weights sum to 1
w >= 0, # No short selling
returns @ w >= 0.11 # Target return of 11%
]
problem = cp.Problem(objective, constraints)
problem.solve()
print(f"Optimal portfolio: {w.value}")
print(f"Expected return: {returns @ w.value:.2%}")
print(f"Portfolio variance: {problem.value:.4f}")
print(f"Portfolio std dev: {np.sqrt(problem.value):.2%}")Basic Example: L1 Regression (Lasso)#
import cvxpy as cp
import numpy as np
# Generate synthetic data
np.random.seed(1)
n, p = 100, 20
X = np.random.randn(n, p)
beta_true = np.zeros(p)
beta_true[:5] = np.array([1, -2, 0.5, -1, 3]) # Sparse true coefficients
y = X @ beta_true + 0.1 * np.random.randn(n)
# Lasso regression: minimize ||Xβ - y||² + λ||β||₁
beta = cp.Variable(p)
lambda_reg = 0.1
objective = cp.Minimize(cp.sum_squares(X @ beta - y) + lambda_reg * cp.norm(beta, 1))
problem = cp.Problem(objective)
problem.solve()
print(f"True coefficients: {beta_true[:5]}")
print(f"Estimated coefficients: {beta.value[:5]}")
print(f"Number of non-zero: {np.sum(np.abs(beta.value) > 0.01)}")Basic Example: Constraint with Norms (SOCP)#
import cvxpy as cp
# Minimize ||x - center||₂ subject to linear constraints
x = cp.Variable(3)
center = np.array([1, 2, 3])
objective = cp.Minimize(cp.norm(x - center, 2))
constraints = [
cp.sum(x) == 9,
x >= 0
]
problem = cp.Problem(objective, constraints)
problem.solve()
print(f"Closest point: {x.value}")
print(f"Distance: {problem.value}")API Design Philosophy#
Algebraic modeling with DCP verification: Express problems naturally while CVXPY ensures convexity.
Advantages:
- Automatic convexity verification: Catch modeling errors at construction time
- Readable code: Mathematical notation
- Solver abstraction: CVXPY reformulates problem for solver capabilities
- Parameters: Separate data from structure, enable rapid re-solves
Disadvantages:
- Limited to convex problems: Cannot handle general nonlinear
- No integer variables (or very limited support via MI-CVXPY)
- DCP learning curve: Must understand convexity rules
Solver Backends#
CVXPY automatically selects appropriate solver based on problem type.
Bundled (Free):#
- Clarabel: Rust-based interior point (default for many problems)
- SCS: Splitting Conic Solver (robust, medium accuracy)
- OSQP: Operator Splitting QP (fast for QP)
- ECOS: Embedded Conic Solver (small to medium SOCP)
- CVXOPT: Python convex optimization
Commercial (if installed):#
- MOSEK: High-performance conic (SOCP, SDP)
- Gurobi: QP and conic support
- CPLEX: QP support
Specialized:#
- GLPK, CBC: LP/MILP via Pyomo interface
- NAG: Numerical Algorithms Group
Specify solver with problem.solve(solver=cp.MOSEK).
When to Use CVXPY#
✅ Good fit when:#
- Problem is convex: LP, convex QP, SOCP, SDP, convex constraints
- Want convexity verification: Prevent modeling errors with DCP
- Machine learning: Lasso, ridge, SVM, logistic regression
- Portfolio optimization: Mean-variance, risk parity
- Signal processing: Filter design, compressed sensing
- Control theory: LQR, MPC with convex constraints
- Parameter tuning: Rapid re-solves with different data (cp.Parameter)
❌ Not suitable when:#
- Integer variables: No MILP support → use PuLP, Pyomo, OR-Tools
- Nonconvex NLP: Non-convex objectives/constraints → use scipy, Pyomo+IPOPT
- Combinatorial optimization: Scheduling, routing → use OR-Tools
- Large-scale MILP: Commercial solvers faster → Gurobi, CPLEX directly
Community and Maturity#
| Metric | Value/Status |
|---|---|
| GitHub stars | Not directly checked (cvxpy/cvxpy) |
| Maturity | Mature (10+ years) |
| Academic roots | Stanford (Stephen Boyd group) |
| Publication | JMLR 2016 (Vol 17, No 83) |
| Maintenance | Active |
| Documentation | Excellent (cvxpy.org) |
| License | Apache 2.0 |
| Courses | Used in Stanford CVX101 (Convex Optimization) |
CVXPY is the standard tool for convex optimization in Python, widely used in academia and industry.
Key Findings from Research#
DCP verification is killer feature: Automatically checks convexity at modeling time. No other Python library does this.
Academic pedigree: Developed by Stephen Boyd’s group at Stanford, based on CVX (MATLAB). Used in teaching convex optimization.
Automatic reformulation: CVXPY transforms your problem into standard conic form for solvers. You model naturally, CVXPY handles the details.
Parameters enable fast re-solves: Declare
cp.Parameterfor data that changes, dramatically faster than rebuilding model.Disciplined Convex Programming (DCP): Ruleset ensures convexity. Learning curve, but catches errors early.
Comparison with Alternatives#
| Feature | CVXPY | Pyomo | scipy.optimize | PuLP |
|---|---|---|---|---|
| Convex optimization | ✅ Best | ✅ Yes | ✅ Yes | ⚠️ LP only |
| DCP verification | ✅ Yes | ❌ No | ❌ No | ❌ No |
| MILP | ❌ No | ✅ Yes | ❌ No | ✅ Yes |
| General NLP | ❌ No | ✅ Yes | ✅ Yes | ❌ No |
| Learning curve | Moderate | Moderate | Easy | Easy |
| Best for | Convex problems | Multi-solver | Prototyping | Simple LP/MILP |
Example Use Cases (Generic)#
Resource Allocation with Quadratic Cost#
Allocate resources to minimize quadratic cost (diminishing returns).
import cvxpy as cp
# Allocate budget across N options with diminishing returns
x = cp.Variable(n_options)
# Quadratic cost (diminishing returns modeled as x^2)
objective = cp.Minimize(cp.sum_squares(x))
constraints = [
cp.sum(x) == total_budget,
x >= min_allocation,
x <= max_allocation
]
problem = cp.Problem(objective, constraints)
problem.solve()Robust Optimization#
Minimize worst-case cost under uncertainty.
import cvxpy as cp
# Worst-case cost over uncertain parameters
x = cp.Variable(n)
u = cp.Variable(m) # Uncertain parameters
# Minimize worst-case objective
objective = cp.Minimize(cp.max(cost_scenarios @ x))
constraints = [
A @ x + B @ u <= b,
cp.norm(u, 2) <= uncertainty_radius, # Uncertainty set
x >= 0
]
problem = cp.Problem(objective, constraints)
problem.solve()Fair Resource Allocation#
Maximize minimum allocation (max-min fairness).
import cvxpy as cp
# Allocate resources fairly (maximize minimum share)
x = cp.Variable(n_users)
min_share = cp.Variable()
objective = cp.Maximize(min_share)
constraints = [
x >= min_share, # Each user gets at least min_share
cp.sum(x) <= total_capacity,
x >= 0
]
problem = cp.Problem(objective, constraints)
problem.solve()Advanced Features#
Parameters for Fast Re-solving#
# Define parameter (data that changes)
lambda_param = cp.Parameter(nonneg=True)
beta = cp.Variable(p)
objective = cp.Minimize(cp.sum_squares(X @ beta - y) + lambda_param * cp.norm(beta, 1))
problem = cp.Problem(objective)
# Solve for different lambda values (fast!)
for lam in [0.01, 0.1, 1.0]:
lambda_param.value = lam
problem.solve(warm_start=True)
print(f"Lambda={lam}: objective={problem.value}")Constraints as Objects#
# Store constraint for later modification
budget_constraint = cp.sum(x) <= budget_param
problem = cp.Problem(objective, [budget_constraint, ...])
# Later, change budget and re-solve
budget_param.value = new_budget
problem.solve()Dual Variables#
# Access dual variables (shadow prices)
problem.solve()
print(f"Dual value: {constraints[0].dual_value}")Problem Classes CVXPY Recognizes#
CVXPY automatically classifies problems for solver selection:
- LP: Linear Programming
- QP: Quadratic Programming
- SOCP: Second-Order Cone Programming (norm constraints)
- SDP: Semidefinite Programming (matrix constraints)
- ExpCone: Exponential cone (entropy, log)
- PowCone: Power cone (geometric programming)
Check with: print(problem.classification)
References#
- Official documentation: https://www.cvxpy.org
- GitHub: https://github.com/cvxpy/cvxpy
- Paper: Diamond & Boyd, “CVXPY: A Python-Embedded Modeling Language for Convex Optimization”, JMLR 2016
- Tutorial: https://www.cvxpy.org/tutorial/
- Book: Boyd & Vandenberghe, “Convex Optimization” (free online)
Summary#
CVXPY is the specialist for convex optimization:
- Automatic convexity verification (DCP analysis)
- Natural mathematical notation
- Excellent for machine learning, portfolio optimization, signal processing
- Stanford academic origins, widely used in education and research
Choose CVXPY when:
- Your problem is convex (or you want to verify it is)
- Machine learning applications (Lasso, SVM, logistic regression)
- Portfolio optimization, control theory, signal processing
- You want to catch modeling errors early with DCP
Look elsewhere for:
- Integer variables (PuLP, Pyomo, OR-Tools)
- General nonlinear (scipy, Pyomo)
- Large-scale MILP (Gurobi, CPLEX)
If your problem is convex, start with CVXPY. The DCP verification alone is worth it.
Google OR-Tools: Industrial-Strength Operations Research#
Overview#
OR-Tools is Google’s open-source operations research toolkit. It provides high-performance solvers for constraint programming (CP), linear/integer programming (LP/MILP), vehicle routing, and graph algorithms. Written in C++ with Python, Java, and C# bindings.
Key finding: With 12.6k GitHub stars, OR-Tools is the most popular open-source optimization framework. Actively maintained by Google with Python 3.13 support as of 2025.
Installation#
pip install ortoolsOR-Tools is self-contained with solvers bundled (no external solver installation required).
Problem Types Supported#
| Problem Type | Supported | Solver/Module |
|---|---|---|
| Linear Programming (LP) | ✅ Yes | GLOP (Google’s LP solver) |
| Mixed-Integer Linear (MILP) | ✅ Yes | SCIP, GLPK, CBC (bundled) |
| Constraint Programming (CP) | ✅ Yes | CP-SAT (Google’s flagship CP solver) |
| Vehicle Routing (VRP) | ✅ Yes | Dedicated routing library |
| Network Flows | ✅ Yes | Min-cost flow, max-flow algorithms |
| Graph Algorithms | ✅ Yes | Shortest paths, assignment |
| Nonlinear Programming (NLP) | ❌ No | Use scipy or Pyomo+IPOPT |
| Convex Optimization | ❌ No | Use CVXPY |
Basic Example: Linear Programming#
from ortools.linear_solver import pywraplp
# Create solver instance
solver = pywraplp.Solver.CreateSolver('GLOP') # Google's LP solver
# Create variables: 0 <= x <= infinity, 0 <= y <= infinity
x = solver.NumVar(0, solver.infinity(), 'x')
y = solver.NumVar(0, solver.infinity(), 'y')
# Create constraints
# Constraint 1: 2x + y <= 20
solver.Add(2 * x + y <= 20)
# Constraint 2: x + 2y <= 20
solver.Add(x + 2 * y <= 20)
# Objective: maximize x + 2y
solver.Maximize(x + 2 * y)
# Solve
status = solver.Solve()
if status == pywraplp.Solver.OPTIMAL:
print(f'Optimal solution found:')
print(f'x = {x.solution_value()}')
print(f'y = {y.solution_value()}')
print(f'Optimal value = {solver.Objective().Value()}')
else:
print('No optimal solution found.')Basic Example: Mixed-Integer Programming#
from ortools.linear_solver import pywraplp
# Create MILP solver (using SCIP backend)
solver = pywraplp.Solver.CreateSolver('SCIP')
# Integer variables: x, y ∈ {0, 1, 2, ...}
x = solver.IntVar(0, solver.infinity(), 'x')
y = solver.IntVar(0, solver.infinity(), 'y')
# Constraints
solver.Add(2 * x + y <= 20)
solver.Add(x + 2 * y <= 20)
# Objective: maximize x + 2y
solver.Maximize(x + 2 * y)
# Solve
status = solver.Solve()
if status == pywraplp.Solver.OPTIMAL:
print(f'x = {x.solution_value()}') # Integer values
print(f'y = {y.solution_value()}')
print(f'Optimal value = {solver.Objective().Value()}')Basic Example: Constraint Programming (CP-SAT)#
CP-SAT is Google’s state-of-the-art constraint programming solver, excellent for scheduling and combinatorial problems.
from ortools.sat.python import cp_model
# Create model
model = cp_model.CpModel()
# Variables with domain [0, 10]
x = model.NewIntVar(0, 10, 'x')
y = model.NewIntVar(0, 10, 'y')
z = model.NewIntVar(0, 10, 'z')
# Constraint: x != y (all different)
model.Add(x != y)
model.Add(y != z)
model.Add(x != z)
# Constraint: x + y + z == 15
model.Add(x + y + z == 15)
# Objective: maximize x * y * z
model.Maximize(x * y * z)
# Solve
solver = cp_model.CpSolver()
status = solver.Solve(model)
if status == cp_model.OPTIMAL:
print(f'x = {solver.Value(x)}')
print(f'y = {solver.Value(y)}')
print(f'z = {solver.Value(z)}')
print(f'Objective = {solver.ObjectiveValue()}')Modules and Components#
OR-Tools is organized into specialized modules:
1. Linear/Integer Programming (linear_solver)#
- GLOP: Google’s LP solver (primal/dual simplex)
- SCIP, CBC, GLPK: Bundled MILP solvers
- External: Can interface with Gurobi, CPLEX if installed
2. Constraint Programming (sat)#
- CP-SAT: Modern SAT-based CP solver
- Excellent for scheduling, assignment, sequencing
- Exploits Boolean satisfiability techniques
- Winner of multiple MiniZinc Challenge medals
3. Vehicle Routing (routing)#
- Specialized solvers for VRP variants
- Rich constraint modeling (time windows, capacities, multiple vehicles)
- Metaheuristics tuned for routing
4. Graph Algorithms (graph)#
- Min-cost flow, max-flow
- Shortest paths
- Assignment problems
- Network optimization
API Design Philosophy#
Object-oriented, solver-specific APIs: Different modules have different APIs (linear_solver vs CP-SAT vs routing).
Advantages:
- High performance (thin Python wrapper over C++)
- Rich features specific to problem type
- Bundled solvers (easy installation)
Disadvantages:
- Different APIs for different problem types (less unified than Pyomo)
- More verbose than algebraic modeling
- Harder to switch between solver types
When to Use OR-Tools#
✅ Good fit when:#
- Constraint programming: Scheduling, sequencing, combinatorial problems → CP-SAT
- Vehicle routing: Delivery routing, technician dispatch → routing module
- Production environment: Stable, high-performance, Google-backed
- Avoid external dependencies: Bundled solvers, no license management
- Integer programming: Strong MILP capability via SCIP
- Graph/network problems: Specialized efficient algorithms
❌ Not suitable when:#
- Nonlinear programming: No NLP support → use scipy, Pyomo+IPOPT, GEKKO
- Convex optimization: No specialized convex solvers → use CVXPY
- Algebraic modeling preference: More verbose than Pyomo/CVXPY
- Academic flexibility: Pyomo supports more solver backends
Solver Backends Available#
Bundled with OR-Tools:#
- GLOP: Google’s LP solver
- CP-SAT: Google’s CP solver
- SCIP: Open-source MILP (Apache 2.0 since 9.0)
- GLPK: GNU Linear Programming Kit
- CBC: COIN-OR Branch and Cut
External (if installed):#
- Gurobi: Commercial MILP
- CPLEX: IBM commercial MILP
- XPRESS: FICO commercial MILP
Use CreateSolver('SOLVER_NAME') to select backend.
Community and Maturity#
| Metric | Value/Status |
|---|---|
| GitHub stars | 12,600 |
| Maturity | Mature (10+ years) |
| Maintenance | Very active (Google) |
| Latest release | Continuous (2025: Python 3.13, muslinux support) |
| Documentation | Excellent (developers.google.com/optimization) |
| License | Apache 2.0 (open source) |
| Contributors | 100+ |
| Python versions | 3.8 - 3.13 |
OR-Tools is production-grade and used extensively at Google and beyond.
Key Findings from Research#
CP-SAT dominance: Google’s CP-SAT solver wins MiniZinc Challenge medals, competitive with commercial CP solvers. Best-in-class for scheduling.
Self-contained: All solvers bundled. No license management, no external compilation. Major usability advantage.
Multiple APIs: Different modules (linear_solver, sat, routing) have distinct APIs. Less unified than Pyomo but more specialized.
Python 3.13 support: As of 2025, OR-Tools supports latest Python versions, showing active maintenance.
Vehicle routing specialization: Dedicated routing library with domain-specific constraints (time windows, capacities, precedence). Unique among Python optimization libraries.
Comparison with Alternatives#
| Feature | OR-Tools | Pyomo | scipy.optimize | PuLP |
|---|---|---|---|---|
| LP/MILP | ✅ Excellent | ✅ Excellent | LP only | ✅ Good |
| Constraint Programming | ✅ Best-in-class | ⚠️ Via external | ❌ No | ❌ No |
| Nonlinear | ❌ No | ✅ Yes | ✅ Yes | ❌ No |
| Vehicle Routing | ✅ Specialized | ❌ No | ❌ No | ❌ No |
| Bundled solvers | ✅ Yes | ❌ No | Partial | ✅ CBC only |
| Modeling style | Object-oriented | Algebraic | Functional | Algebraic |
| API complexity | Moderate | Moderate | Easy | Easy |
Example Use Cases (Generic)#
Resource Assignment with Constraints#
Assign tasks to workers subject to skill requirements, availability, workload limits.
from ortools.sat.python import cp_model
model = cp_model.CpModel()
# Binary variables: worker_task[w, t] = 1 if worker w assigned to task t
worker_task = {}
for w in workers:
for t in tasks:
worker_task[w, t] = model.NewBoolVar(f'worker_{w}_task_{t}')
# Each task assigned to exactly one worker
for t in tasks:
model.Add(sum(worker_task[w, t] for w in workers) == 1)
# Worker workload limits
for w in workers:
model.Add(sum(duration[t] * worker_task[w, t] for t in tasks) <= max_workload[w])
# Minimize total cost
model.Minimize(sum(cost[w, t] * worker_task[w, t]
for w in workers for t in tasks))
solver = cp_model.CpSolver()
solver.Solve(model)Scheduling with No-Overlap#
Schedule jobs on machines with no time overlap.
from ortools.sat.python import cp_model
model = cp_model.CpModel()
# Interval variables for each job
intervals = []
for j in jobs:
start = model.NewIntVar(0, horizon, f'start_{j}')
duration = durations[j]
end = model.NewIntVar(0, horizon, f'end_{j}')
interval = model.NewIntervalVar(start, duration, end, f'interval_{j}')
intervals.append(interval)
# No overlap constraint
model.AddNoOverlap(intervals)
# Minimize makespan (max end time)
makespan = model.NewIntVar(0, horizon, 'makespan')
for j in jobs:
model.Add(makespan >= intervals[j].EndExpr())
model.Minimize(makespan)Network Flow Problem#
Route flow through network minimizing cost.
from ortools.graph import pywrapgraph
# Create min-cost flow solver
min_cost_flow = pywrapgraph.SimpleMinCostFlow()
# Add arcs: (source, destination, capacity, unit_cost)
for source, dest, capacity, cost in arcs:
min_cost_flow.AddArcWithCapacityAndUnitCost(source, dest, capacity, cost)
# Set supply/demand at nodes
for node, supply in supplies.items():
min_cost_flow.SetNodeSupply(node, supply)
# Solve
status = min_cost_flow.Solve()
if status == min_cost_flow.OPTIMAL:
print(f'Minimum cost: {min_cost_flow.OptimalCost()}')
for arc in range(min_cost_flow.NumArcs()):
if min_cost_flow.Flow(arc) > 0:
print(f'Arc {arc}: flow = {min_cost_flow.Flow(arc)}')Performance Characteristics#
- LP (GLOP): Competitive with open-source solvers (GLPK, CLP), somewhat slower than commercial
- MILP (SCIP): Good performance, especially for structured problems
- CP-SAT: Excellent for scheduling and combinatorial problems, award-winning
- Routing: Highly optimized metaheuristics for vehicle routing variants
For maximum MILP performance on large instances, commercial solvers (Gurobi, CPLEX) still faster, but OR-Tools competitive for many practical problems.
References#
- Official documentation: https://developers.google.com/optimization
- GitHub repository: https://github.com/google/or-tools (12.6k stars)
- Examples: https://github.com/google/or-tools/tree/stable/examples/python
- CP-SAT: https://developers.google.com/optimization/cp/cp_solver
Summary#
OR-Tools is a comprehensive, production-ready optimization toolkit with:
- Best-in-class constraint programming (CP-SAT)
- Specialized vehicle routing solvers
- Bundled MILP solvers (SCIP, CBC, GLPK)
- Google backing and active development
Choose OR-Tools for:
- Scheduling, sequencing, combinatorial problems (CP-SAT)
- Vehicle routing and logistics
- Production environments requiring stable, maintained library
- Projects avoiding external solver installation
Look elsewhere for nonlinear programming, convex optimization, or algebraic modeling preference.
PuLP: Linear Programming in Python#
Overview#
PuLP is a linear and mixed-integer programming modeler written in Python. It is designed to be simple and accessible for LP/MILP problems, with an algebraic modeling interface and the CBC solver bundled by default.
Key finding: PuLP 3.3.0 (Sept 2025) offers the easiest entry point for LP/MILP optimization in Python. Part of COIN-OR project with MIT license. CBC solver included means zero external dependencies for basic use.
Installation#
pip install pulpThe CBC (COIN-OR Branch and Cut) solver is bundled, so you can solve MILP problems immediately without additional installation.
Problem Types Supported#
PuLP is focused exclusively on linear programming:
| Problem Type | Supported | Notes |
|---|---|---|
| Linear Programming (LP) | ✅ Yes | Continuous variables only |
| Mixed-Integer Linear (MILP) | ✅ Yes | Integer and binary variables |
| Quadratic Programming (QP) | ❌ No | Use CVXPY or Pyomo |
| Nonlinear Programming (NLP) | ❌ No | Use scipy or Pyomo |
| Constraint Programming | ❌ No | Use OR-Tools |
Philosophy: Do one thing well. PuLP targets LP/MILP with simple, clean API.
Basic Example: Linear Programming#
from pulp import *
# Create problem
prob = LpProblem("Example", LpMaximize)
# Variables
x = LpVariable("x", lowBound=0)
y = LpVariable("y", lowBound=0)
# Objective: maximize x + 2y
prob += x + 2*y, "Objective"
# Constraints
prob += 2*x + y <= 20, "Constraint1"
prob += x + 2*y <= 20, "Constraint2"
# Solve with bundled CBC solver
prob.solve()
# Results
print(f"Status: {LpStatus[prob.status]}")
print(f"Optimal value: {value(prob.objective)}")
print(f"x = {value(x)}")
print(f"y = {value(y)}")Basic Example: Integer Programming#
from pulp import *
prob = LpProblem("Integer_Example", LpMaximize)
# Integer variables
x = LpVariable("x", lowBound=0, cat='Integer')
y = LpVariable("y", lowBound=0, cat='Integer')
# Objective
prob += x + 2*y
# Constraints
prob += 2*x + y <= 20
prob += x + 2*y <= 20
# Solve
prob.solve(PULP_CBC_CMD(msg=0)) # msg=0 suppresses solver output
print(f"x = {value(x)}") # Integer value
print(f"y = {value(y)}") # Integer value
print(f"Optimal value: {value(prob.objective)}")Basic Example: Binary Selection Problem#
from pulp import *
# Select subset of projects to maximize value subject to budget
projects = ['A', 'B', 'C', 'D']
costs = {'A': 10, 'B': 15, 'C': 12, 'D': 8}
values = {'A': 20, 'B': 30, 'C': 25, 'D': 15}
budget = 30
prob = LpProblem("Project_Selection", LpMaximize)
# Binary variables: select[p] = 1 if project p is selected
select = LpVariable.dicts("select", projects, cat='Binary')
# Objective: maximize total value
prob += lpSum([values[p] * select[p] for p in projects])
# Budget constraint
prob += lpSum([costs[p] * select[p] for p in projects]) <= budget
# Solve
prob.solve()
# Display selected projects
print("Selected projects:")
for p in projects:
if value(select[p]) == 1:
print(f" {p}: value={values[p]}, cost={costs[p]}")
print(f"Total value: {value(prob.objective)}")Basic Example: Multi-Index Variables#
from pulp import *
# Transportation problem: ship products from factories to warehouses
factories = ['F1', 'F2', 'F3']
warehouses = ['W1', 'W2', 'W3', 'W4']
supply = {'F1': 100, 'F2': 150, 'F3': 120}
demand = {'W1': 80, 'W2': 70, 'W3': 90, 'W4': 60}
cost = { # cost[factory, warehouse]
('F1', 'W1'): 2, ('F1', 'W2'): 4, ('F1', 'W3'): 5, ('F1', 'W4'): 3,
('F2', 'W1'): 3, ('F2', 'W2'): 1, ('F2', 'W3'): 3, ('F2', 'W4'): 2,
('F3', 'W1'): 5, ('F3', 'W2'): 4, ('F3', 'W3'): 2, ('F3', 'W4'): 3,
}
prob = LpProblem("Transportation", LpMinimize)
# Variables: flow[f, w] = amount shipped from factory f to warehouse w
routes = [(f, w) for f in factories for w in warehouses]
flow = LpVariable.dicts("flow", routes, lowBound=0)
# Objective: minimize total transportation cost
prob += lpSum([cost[f, w] * flow[f, w] for (f, w) in routes])
# Supply constraints: don't exceed factory capacity
for f in factories:
prob += lpSum([flow[f, w] for w in warehouses]) <= supply[f]
# Demand constraints: meet warehouse demand
for w in warehouses:
prob += lpSum([flow[f, w] for f in factories]) >= demand[w]
# Solve
prob.solve()
print(f"Total cost: {value(prob.objective)}")
for (f, w) in routes:
if value(flow[f, w]) > 0:
print(f"Ship {value(flow[f, w])} from {f} to {w}")API Design Philosophy#
Algebraic modeling with Python syntax: Use Python operators (+, -, *, <=, >=, ==) naturally.
Advantages:
- Simple to learn: Minimal concepts (LpProblem, LpVariable, constraints)
- Pythonic: Uses Python operators, dictionaries, list comprehensions
- Bundled solver: CBC included, works immediately
- Lightweight: Focused API, not trying to do everything
- Readable: Models look like mathematical formulations
Disadvantages:
- Limited to LP/MILP: No nonlinear, no constraint programming
- Less flexible than Pyomo: Fewer solver options, less extensible
- Performance: For maximum MILP performance, commercial solvers (Gurobi) faster
Solver Backends#
PuLP interfaces with multiple LP/MILP solvers:
Bundled (Included):#
- CBC (COIN-OR Branch and Cut): Default, good quality open-source MILP solver
External (if installed):#
- GLPK: GNU Linear Programming Kit
- HiGHS: Modern high-performance LP/MIP solver
- Gurobi: Commercial (fast, requires license)
- CPLEX: IBM commercial (requires license)
- XPRESS: FICO commercial (requires license)
- SCIP: Open-source MILP/MINLP
- MOSEK: Commercial conic solver
Specify solver: prob.solve(GLPK()), prob.solve(GUROBI()), etc.
Install solvers via extras: pip install pulp[gurobi], pip install pulp[highs]
When to Use PuLP#
✅ Good fit when:#
- LP or MILP problems: Linear objective and constraints with integer variables
- Getting started: Learning optimization, simple problems
- Rapid prototyping: Quick experiments, proof of concept
- No external dependencies wanted: CBC bundled, works immediately
- Small to medium problems: Thousands of variables
- Occasional optimization: Not building optimization-heavy systems
❌ Not suitable when:#
- Nonlinear problems: No NLP support → use scipy, Pyomo, GEKKO
- Constraint programming: Scheduling, sequencing → use OR-Tools CP-SAT
- Convex optimization: SOCP, SDP → use CVXPY
- Need many solvers: Pyomo supports 20+ solvers, PuLP has fewer
- Very large MILP: For maximum performance, use Gurobi/CPLEX directly
Community and Maturity#
| Metric | Value/Status |
|---|---|
| Latest version | 3.3.0 (September 2025) |
| Maturity | Mature (15+ years) |
| Part of | COIN-OR (Computational Infrastructure for Operations Research) |
| Maintenance | Active (recent releases) |
| Documentation | Good (coin-or.github.io/pulp) |
| License | MIT (permissive) |
| Python versions | 3.9+ |
| Repository | github.com/coin-or/pulp |
PuLP is a mature, stable library with active maintenance. Part of respected COIN-OR project.
Key Findings from Research#
Easiest entry point: Simplest API among algebraic modeling languages. Good for teaching and learning.
CBC bundled: Major usability advantage. No solver installation required. CBC is respectable open-source MILP solver.
Version 3.3.0 (Sept 2025): Recent release shows active maintenance. Requires Python 3.9+.
HiGHS support: Can use HiGHS (the rising star open-source solver adopted by SciPy and MATLAB) via
pip install pulp[highs].COIN-OR ecosystem: Part of mature operations research ecosystem (CBC, CLP, GLPK all COIN-OR projects).
Comparison with Alternatives#
| Feature | PuLP | Pyomo | CVXPY | OR-Tools |
|---|---|---|---|---|
| Problem types | LP, MILP | LP, MILP, NLP, MINLP | Convex | LP, MILP, CP |
| Simplicity | ⭐⭐⭐ Easy | ⭐⭐ Moderate | ⭐⭐ Moderate | ⭐⭐ Moderate |
| Bundled solver | ✅ CBC | ❌ No | ✅ Multiple | ✅ Multiple |
| Solver flexibility | ⭐⭐ Good | ⭐⭐⭐ Excellent | ⭐⭐ Good | ⭐ Limited |
| Performance | Good | Good | Good | Excellent (CP-SAT) |
| Best for | Simple LP/MILP | Research, multi-solver | Convex problems | Production, CP |
Example Use Cases (Generic)#
Blending Problem#
Mix ingredients to meet requirements at minimum cost.
from pulp import *
# Blend ingredients to meet nutrient requirements
ingredients = ['A', 'B', 'C']
nutrients = ['protein', 'fiber', 'fat']
# Cost per unit
cost = {'A': 2.0, 'B': 3.5, 'C': 1.8}
# Nutrient content per unit
content = {
('A', 'protein'): 0.10, ('A', 'fiber'): 0.05, ('A', 'fat'): 0.02,
('B', 'protein'): 0.15, ('B', 'fiber'): 0.08, ('B', 'fat'): 0.03,
('C', 'protein'): 0.08, ('C', 'fiber'): 0.12, ('C', 'fat'): 0.01,
}
# Minimum nutrient requirements
requirements = {'protein': 10, 'fiber': 6, 'fat': 2}
prob = LpProblem("Blending", LpMinimize)
# Variables: amount of each ingredient
x = LpVariable.dicts("ingredient", ingredients, lowBound=0)
# Objective: minimize cost
prob += lpSum([cost[i] * x[i] for i in ingredients])
# Nutrient constraints
for n in nutrients:
prob += lpSum([content[i, n] * x[i] for i in ingredients]) >= requirements[n]
prob.solve()
print(f"Minimum cost: {value(prob.objective):.2f}")
for i in ingredients:
print(f"Ingredient {i}: {value(x[i]):.2f} units")Cutting Stock Problem#
Cut raw materials to required lengths minimizing waste.
from pulp import *
# Cut stock of length 100 into required pieces
stock_length = 100
required_pieces = {30: 5, 40: 3, 50: 2} # {length: quantity}
# Generate cutting patterns (simplified)
patterns = [
{30: 3, 40: 0, 50: 0}, # Three 30s
{30: 1, 40: 1, 50: 0}, # One 30, one 40
{30: 0, 40: 2, 50: 0}, # Two 40s
{30: 0, 40: 0, 50: 2}, # Two 50s
{30: 1, 40: 0, 50: 1}, # One 30, one 50
]
prob = LpProblem("Cutting_Stock", LpMinimize)
# Variables: number of times each pattern is used
use_pattern = LpVariable.dicts("pattern", range(len(patterns)), lowBound=0, cat='Integer')
# Objective: minimize number of stocks used
prob += lpSum([use_pattern[p] for p in range(len(patterns))])
# Meet demand for each piece length
for length, quantity in required_pieces.items():
prob += lpSum([patterns[p][length] * use_pattern[p]
for p in range(len(patterns))]) >= quantity
prob.solve()
print(f"Minimum stocks needed: {value(prob.objective)}")
for p in range(len(patterns)):
if value(use_pattern[p]) > 0:
print(f"Pattern {p}: use {value(use_pattern[p])} times - {patterns[p]}")Facility Location#
Decide which facilities to open and how to serve customers.
from pulp import *
# Same as earlier example in or-tools.md
# (Facility location with fixed costs and transportation)
# ... (code similar to OR-Tools example but using PuLP syntax)Advanced Features#
Multiple Objectives (Lexicographic)#
Solve for primary objective, then optimize secondary subject to primary being optimal.
# First solve for primary objective
prob.solve()
primary_optimal = value(prob.objective)
# Add constraint that primary stays optimal
prob += primary_objective == primary_optimal
# Change to secondary objective
prob.sense = LpMinimize
prob.setObjective(secondary_objective)
prob.solve()Constraint Names and Access#
# Named constraints for later reference
prob += (x + y <= 10, "capacity_constraint")
# Access constraint
for name, constraint in prob.constraints.items():
print(f"{name}: {constraint}")Variable Bounds and Categories#
# Different variable types
x = LpVariable("x", lowBound=0) # x >= 0
y = LpVariable("y", lowBound=0, upBound=10) # 0 <= y <= 10
z = LpVariable("z", cat='Integer') # Integer
b = LpVariable("b", cat='Binary') # Binary (0 or 1)Writing Problem to File#
# Export to LP format for inspection or use with external tools
prob.writeLP("model.lp")Performance Tips#
- Use CBC for general MILP: Bundled, good performance
- Use HiGHS for large LP: Install with
pip install pulp[highs], faster than CBC for LP - Use Gurobi for large MILP: If performance critical and license available
- Formulation matters: Tight formulations solve faster than loose ones
- Use appropriate variable types: Don’t use
IntegerifContinuousworks
Solver Selection Example#
from pulp import *
prob = LpProblem("Example", LpMaximize)
# ... define variables, objective, constraints ...
# Try different solvers
# prob.solve(PULP_CBC_CMD()) # Default bundled CBC
# prob.solve(HiGHS_CMD()) # HiGHS (if installed)
# prob.solve(GUROBI_CMD()) # Gurobi (if licensed)
# prob.solve(CPLEX_CMD()) # CPLEX (if licensed)
# prob.solve(GLPK_CMD()) # GLPK (if installed)
# With options
prob.solve(PULP_CBC_CMD(msg=1, timeLimit=60)) # Show output, 60s limitReferences#
- Official documentation: https://coin-or.github.io/pulp/
- GitHub repository: https://github.com/coin-or/pulp
- COIN-OR: https://www.coin-or.org/
- Tutorials: https://coin-or.github.io/pulp/CaseStudies/index.html
Summary#
PuLP is the simplest path to LP/MILP optimization in Python:
- Easy to learn and use
- CBC solver bundled (works immediately)
- Clean algebraic modeling interface
- Mature and stable (COIN-OR project)
- Good for small to medium problems
Choose PuLP when:
- Getting started with optimization
- LP or MILP problems (no nonlinear)
- Want bundled solver (no installation hassles)
- Rapid prototyping
- Teaching or learning
Look elsewhere for:
- Nonlinear problems (scipy, Pyomo, GEKKO)
- Constraint programming (OR-Tools)
- Convex optimization with verification (CVXPY)
- Maximum solver flexibility (Pyomo’s 20+ backends)
- Large-scale performance (direct Gurobi/CPLEX API)
If you’re solving LP/MILP and want the easiest path, start with PuLP.
Pyomo: Python Optimization Modeling Objects#
Overview#
Pyomo is a Python-based open-source software package for formulating and analyzing optimization models. It is an algebraic modeling language (AML) that allows you to express optimization problems using mathematical notation, similar to AMPL or GAMS.
Key finding: With 2,127 GitHub stars and 123,641 weekly downloads, Pyomo is the leading Python algebraic modeling language, offering interfaces to 20+ solver backends.
Installation#
# Basic installation
pip install pyomo
# With optional solver interfaces
pip install pyomo[optional]Note: Pyomo is a modeling language, not a solver. You must install solvers separately (GLPK, CBC, IPOPT, Gurobi, etc.).
Problem Types Supported#
Pyomo supports virtually all optimization problem types through its extensible architecture:
| Problem Type | Supported | Notes |
|---|---|---|
| Linear Programming (LP) | ✅ Yes | Via GLPK, CBC, HiGHS, Gurobi, CPLEX, etc. |
| Mixed-Integer Linear (MILP) | ✅ Yes | All MILP solvers |
| Quadratic Programming (QP) | ✅ Yes | Via Gurobi, CPLEX, MOSEK |
| Nonlinear Programming (NLP) | ✅ Yes | Via IPOPT, SNOPT, KNITRO, BARON |
| Mixed-Integer NLP (MINLP) | ✅ Yes | Via BARON, Couenne, BONMIN |
| Stochastic Programming | ✅ Yes | PySP extension |
| Dynamic Optimization | ✅ Yes | Pyomo.DAE for differential-algebraic equations |
| Disjunctive Programming | ✅ Yes | GDP extension (generalized disjunctive programming) |
Pyomo’s strength is solver flexibility: same model code can be solved with different backends.
Basic Example: Linear Programming#
from pyomo.environ import *
# Create a concrete model
model = ConcreteModel()
# Decision variables
model.x = Var(domain=NonNegativeReals)
model.y = Var(domain=NonNegativeReals)
# Objective: maximize x + 2y
model.obj = Objective(expr=model.x + 2*model.y, sense=maximize)
# Constraints
model.con1 = Constraint(expr=2*model.x + model.y <= 20)
model.con2 = Constraint(expr=model.x + 2*model.y <= 20)
# Solve with GLPK (open-source LP solver)
solver = SolverFactory('glpk')
result = solver.solve(model, tee=True) # tee=True shows solver output
# Display results
print(f"x = {value(model.x)}")
print(f"y = {value(model.y)}")
print(f"Objective = {value(model.obj)}")Basic Example: Mixed-Integer Programming#
from pyomo.environ import *
model = ConcreteModel()
# Integer decision variables
model.x = Var(domain=NonNegativeIntegers)
model.y = Var(domain=NonNegativeIntegers)
# Objective
model.obj = Objective(expr=model.x + 2*model.y, sense=maximize)
# Constraints
model.con1 = Constraint(expr=2*model.x + model.y <= 20)
model.con2 = Constraint(expr=model.x + 2*model.y <= 20)
# Solve with CBC (open-source MILP solver)
solver = SolverFactory('cbc')
result = solver.solve(model)
print(f"x = {value(model.x)}") # Integer value
print(f"y = {value(model.y)}") # Integer value
print(f"Objective = {value(model.obj)}")Basic Example: Nonlinear Programming#
from pyomo.environ import *
model = ConcreteModel()
# Variables with bounds
model.x = Var(bounds=(0, 10), initialize=5)
model.y = Var(bounds=(0, 10), initialize=5)
# Nonlinear objective
model.obj = Objective(expr=model.x**2 + model.y**2)
# Nonlinear constraint
model.con1 = Constraint(expr=model.x**2 + model.y >= 4)
# Solve with IPOPT (open-source NLP solver)
solver = SolverFactory('ipopt')
result = solver.solve(model, tee=False)
print(f"x = {value(model.x)}")
print(f"y = {value(model.y)}")
print(f"Objective = {value(model.obj)}")Basic Example: Indexed Variables and Constraints#
Pyomo excels at modeling problems with sets and indices:
from pyomo.environ import *
model = ConcreteModel()
# Sets
model.PROJECTS = Set(initialize=['A', 'B', 'C', 'D'])
# Parameters (data)
cost = {'A': 10, 'B': 15, 'C': 12, 'D': 8}
return_val = {'A': 20, 'B': 30, 'C': 25, 'D': 15}
model.budget = Param(initialize=30)
# Indexed binary variables: select[p] = 1 if project p is selected
model.select = Var(model.PROJECTS, domain=Binary)
# Objective: maximize total return
model.obj = Objective(
expr=sum(return_val[p] * model.select[p] for p in model.PROJECTS),
sense=maximize
)
# Budget constraint
model.budget_con = Constraint(
expr=sum(cost[p] * model.select[p] for p in model.PROJECTS) <= model.budget
)
# Solve
solver = SolverFactory('cbc')
solver.solve(model)
# Display selected projects
print("Selected projects:")
for p in model.PROJECTS:
if value(model.select[p]) > 0.5: # Binary variable
print(f" {p}: return = {return_val[p]}, cost = {cost[p]}")API Design Philosophy#
Algebraic modeling language: Express models using mathematical notation close to textbook formulations.
Advantages:
- Readable models (looks like mathematics)
- Separation of model and data
- Reusable model structure
- Easy to modify and extend
- Solver-agnostic (change solver with one line)
- Structured indexing (sets, parameters, indexed variables)
Disadvantages:
- Learning curve (new syntax and concepts)
- More verbose than direct solver APIs for simple problems
- Overhead for very small problems
- Requires understanding of both Pyomo syntax and optimization theory
Solver Backends (20+ supported)#
Pyomo interfaces with external solvers via file-based or direct API communication.
Open-Source Linear/Integer#
- GLPK: GNU Linear Programming Kit
- CBC: COIN-OR Branch and Cut
- HiGHS: High-performance LP/MIP solver
Open-Source Nonlinear#
- IPOPT: Interior Point OPTimizer (large-scale NLP)
- Couenne: Convex Over and Under ENvelopes for NLP (MINLP)
- BONMIN: Basic Open-source Nonlinear Mixed INteger (MINLP)
Commercial#
- Gurobi: Leading commercial MILP/QP solver
- CPLEX: IBM commercial solver
- MOSEK: Conic optimization specialist
- XPRESS: FICO solver
- KNITRO: Nonlinear optimization
- BARON: Global MINLP solver
Specialized#
- Mindtpy: Pyomo’s built-in MINLP solver
- SCIP: Open-source MILP/MINLP
- GDPopt: Generalized disjunctive programming
Use SolverFactory('solver_name') to select solver.
When to Use Pyomo#
✅ Good fit when:#
- Complex models: Many constraints, indexed variables, reusable structure
- Solver flexibility: Want to try multiple solvers (CBC, Gurobi, IPOPT) on same model
- Academic research: Need to document model structure, try different formulations
- Data-driven models: Separate model logic from data, load data from files/databases
- Mixed problem types: LP, MILP, NLP in same project
- Advanced features: Stochastic programming, disjunctive programming, DAE systems
- Model archival: Mathematical formulation readable years later
❌ Not suitable when:#
- Simple one-off problems: scipy.optimize or PuLP simpler
- Constraint programming: OR-Tools CP-SAT better for scheduling
- Convex optimization: CVXPY provides DCP verification
- Maximum performance: Direct solver APIs (gurobipy) slightly faster
- No solver installation: Pyomo requires external solvers (unlike OR-Tools)
Community and Maturity#
| Metric | Value/Status |
|---|---|
| GitHub stars | 2,127 |
| Downloads | 123,641 per week (PyPI) |
| Maturity | Mature (15+ years) |
| Maintenance | Active (Pyomo v6.9.4, Sept 2025) |
| Documentation | Excellent (pyomo.readthedocs.io, textbook available) |
| License | BSD (permissive) |
| Python versions | 3.8+ (3.8 dropped in 6.9.3) |
| Contributors | 100+ |
Pyomo is the academic standard for optimization modeling in Python. Used extensively in research and teaching.
Key Findings from Research#
Ecosystem leader: 20+ solver interfaces make Pyomo the most flexible Python modeling language for solver experimentation.
Active development: Regular releases (v6.9.4 in 2025), new features like logic-based discrete steepest descent in GDPopt.
Extensions: Pyomo.DAE (differential-algebraic equations), PySP (stochastic programming), GDP (disjunctive programming) enable advanced problem types.
Educational adoption: Many universities use Pyomo for teaching optimization. Textbook “Pyomo — Optimization Modeling in Python” available.
Academic roots: Developed at Sandia National Laboratories, widely used in energy systems, chemical engineering, operations research.
Comparison with Alternatives#
| Feature | Pyomo | CVXPY | PuLP | OR-Tools |
|---|---|---|---|---|
| Problem types | LP, MILP, NLP, MINLP | Convex only | LP, MILP | LP, MILP, CP |
| Solver backends | 20+ | 10+ | 10+ | Bundled |
| Modeling style | Algebraic | Algebraic (DCP) | Algebraic | Object-oriented |
| Learning curve | Moderate | Moderate | Easy | Moderate |
| Flexibility | Highest | Medium | Medium | Lower |
| Performance overhead | Low | Low | Low | Very low |
| Best for | Multi-solver research | Convex problems | Simple LP/MILP | Production, CP |
Example Use Cases (Generic)#
Production Planning with Time Periods#
Determine production quantities over time to minimize cost while meeting demand.
from pyomo.environ import *
model = ConcreteModel()
# Sets
model.PRODUCTS = Set(initialize=['A', 'B', 'C'])
model.PERIODS = RangeSet(1, 12) # 12 time periods
# Parameters (data)
model.demand = Param(model.PRODUCTS, model.PERIODS, initialize=demand_data)
model.production_cost = Param(model.PRODUCTS, initialize=prod_cost_data)
model.inventory_cost = Param(model.PRODUCTS, initialize=inv_cost_data)
model.capacity = Param(model.PERIODS, initialize=capacity_data)
# Variables
model.produce = Var(model.PRODUCTS, model.PERIODS, domain=NonNegativeReals)
model.inventory = Var(model.PRODUCTS, model.PERIODS, domain=NonNegativeReals)
# Objective: minimize total cost
def total_cost_rule(m):
return sum(m.production_cost[p] * m.produce[p, t] +
m.inventory_cost[p] * m.inventory[p, t]
for p in m.PRODUCTS for t in m.PERIODS)
model.obj = Objective(rule=total_cost_rule, sense=minimize)
# Inventory balance constraints
def inventory_balance_rule(m, p, t):
if t == 1:
return m.inventory[p, t] == m.produce[p, t] - m.demand[p, t]
else:
return m.inventory[p, t] == m.inventory[p, t-1] + m.produce[p, t] - m.demand[p, t]
model.inventory_balance = Constraint(model.PRODUCTS, model.PERIODS, rule=inventory_balance_rule)
# Capacity constraint
def capacity_rule(m, t):
return sum(m.produce[p, t] for p in m.PRODUCTS) <= m.capacity[t]
model.capacity_con = Constraint(model.PERIODS, rule=capacity_rule)
solver = SolverFactory('glpk')
solver.solve(model)Network Design with Fixed Costs#
Select facilities to open (binary decisions) and route flows to minimize total cost.
from pyomo.environ import *
model = ConcreteModel()
model.FACILITIES = Set(initialize=['F1', 'F2', 'F3'])
model.CUSTOMERS = Set(initialize=['C1', 'C2', 'C3', 'C4'])
# Binary: open facility or not
model.open = Var(model.FACILITIES, domain=Binary)
# Continuous: flow from facility to customer
model.flow = Var(model.FACILITIES, model.CUSTOMERS, domain=NonNegativeReals)
# Objective: minimize fixed costs + variable costs
def total_cost_rule(m):
fixed = sum(fixed_cost[f] * m.open[f] for f in m.FACILITIES)
variable = sum(transport_cost[f, c] * m.flow[f, c]
for f in m.FACILITIES for c in m.CUSTOMERS)
return fixed + variable
model.obj = Objective(rule=total_cost_rule, sense=minimize)
# Meet customer demand
def demand_rule(m, c):
return sum(m.flow[f, c] for f in m.FACILITIES) >= demand[c]
model.demand_con = Constraint(model.CUSTOMERS, rule=demand_rule)
# Facility capacity (only if open)
def capacity_rule(m, f):
return sum(m.flow[f, c] for c in m.CUSTOMERS) <= capacity[f] * m.open[f]
model.capacity_con = Constraint(model.FACILITIES, rule=capacity_rule)
solver = SolverFactory('cbc')
solver.solve(model)Performance Characteristics#
Pyomo adds modest overhead for:
- Model construction (building expression trees)
- Communication with solver (file-based or API)
For large models (10,000+ variables), overhead typically <10% of total solve time. Solver performance dominates.
Tips for performance:
- Use indexed variables/constraints instead of loops
- Choose fast solvers (Gurobi > CBC for MILP)
- Consider direct API interfaces (pyomo-gurobi-direct) for large models
Advanced Features#
Abstract Models#
Separate model structure from data:
model = AbstractModel()
# Define structure with undefined parameters
model.load('data.dat') # Load data laterPersistent Solvers#
Reuse solver instance across multiple solves (incremental changes):
solver = SolverFactory('gurobi', solver_io='python')
solver.set_instance(model)
solver.solve()
# Modify model
solver.solve() # Incremental solveSuffixes#
Access solver-specific information (dual values, reduced costs):
model.dual = Suffix(direction=Suffix.IMPORT)
solver.solve(model)
print(model.dual[model.con1]) # Dual value of constraintReferences#
- Official documentation: https://pyomo.readthedocs.io
- GitHub: https://github.com/Pyomo/pyomo (2.1k stars)
- Textbook: Bynum et al., “Pyomo — Optimization Modeling in Python”, Springer
- Website: http://www.pyomo.org
Summary#
Pyomo is the most comprehensive Python optimization modeling language:
- 20+ solver backends (most flexible)
- All problem types (LP, MILP, NLP, MINLP, stochastic, dynamic)
- Algebraic modeling for complex, structured problems
- Academic standard for optimization research
Choose Pyomo when:
- You need solver flexibility (try Gurobi, CBC, IPOPT on same model)
- Model complexity justifies algebraic modeling overhead
- Academic research or teaching
- Advanced features (stochastic, disjunctive, DAE)
Look elsewhere for:
- Simple one-off problems (scipy.optimize, PuLP)
- Convex with verification (CVXPY)
- Constraint programming (OR-Tools)
- Maximum performance (direct APIs)
S1-Rapid: Library Selection Recommendations#
Executive Summary#
Based on research of Python optimization libraries (PyPI statistics, GitHub activity, documentation quality, and community feedback), selection depends primarily on problem type, followed by solver flexibility needs and simplicity requirements.
Key insight: Problem type (LP, MILP, NLP, convex) is the dominant selection criterion, not application domain.
Quick Decision Tree#
What problem type?
│
├─ Linear/Integer Programming (LP/MILP)?
│ ├─ Simple, one-off problem? → PuLP (easiest)
│ ├─ Need solver flexibility? → Pyomo (20+ solvers)
│ ├─ Production, constraint programming? → OR-Tools (CP-SAT)
│ └─ Already using scipy? → scipy.optimize.linprog (HiGHS backend)
│
├─ Convex Optimization?
│ └─ CVXPY (DCP verification, specialized solvers)
│
├─ Nonlinear Programming (NLP)?
│ ├─ Small-medium scale? → scipy.optimize (BFGS, SLSQP)
│ ├─ Large scale or need solvers? → Pyomo + IPOPT
│ └─ Dynamic optimization / DAE? → GEKKO
│
├─ Multi-Objective?
│ └─ pymoo (Pareto frontier, genetic algorithms)
│
└─ Constraint Programming / Scheduling?
└─ OR-Tools CP-SAT (best-in-class)Detailed Recommendations by Scenario#
Scenario 1: Getting Started / Learning#
Recommendation: PuLP (if LP/MILP) or scipy.optimize (if continuous)
Rationale:
- PuLP: Simplest algebraic modeling for LP/MILP, CBC bundled
- scipy.optimize: Zero installation (part of scipy), good for continuous problems
- Both have gentle learning curves and excellent documentation
Example: Student learning optimization, analyst solving occasional problems
Scenario 2: Rapid Prototyping#
Recommendation: scipy.optimize (continuous) or PuLP (discrete)
Rationale:
- Fast to code, minimal boilerplate
- Good for experiments and proof-of-concept
- Can graduate to more powerful tools later
Example: Researcher testing optimization approach, data scientist exploring models
Scenario 3: Production LP/MILP#
Recommendation: OR-Tools or Pyomo + HiGHS/Gurobi
Rationale:
- OR-Tools: Google-maintained, bundled solvers, excellent performance (CP-SAT), production-ready
- Pyomo + HiGHS: Open-source, competitive performance, flexible
- Pyomo + Gurobi: Maximum performance if license available
Example: Logistics optimization service, resource allocation system, production planning application
Scenario 4: Convex Optimization#
Recommendation: CVXPY
Rationale:
- Automatic convexity verification (DCP analysis)
- Specialized solvers for convex problems
- Standard tool for machine learning, portfolio optimization, signal processing
Example: Portfolio optimization, Lasso/ridge regression, SVM training, control systems
Scenario 5: Nonlinear Programming#
Recommendation: scipy.optimize (small-medium) or Pyomo + IPOPT (large)
Rationale:
- scipy.optimize: Built-in, good algorithms (BFGS, trust-region), handles constraints
- Pyomo + IPOPT: Large-scale NLP, more solver options, algebraic modeling
Example: Parameter estimation, engineering design optimization, calibration against simulation
Scenario 6: Scheduling / Combinatorial#
Recommendation: OR-Tools CP-SAT
Rationale:
- Best-in-class constraint programming solver
- Specialized for scheduling, sequencing, assignment
- MiniZinc Challenge winner
Example: Job shop scheduling, employee rostering, task assignment, timetabling
Scenario 7: Vehicle Routing#
Recommendation: OR-Tools routing module
Rationale:
- Specialized routing solvers
- Rich constraint modeling (time windows, capacities, precedence)
- Tuned metaheuristics
Example: Delivery routing, technician dispatch, field service optimization
Scenario 8: Academic Research / Multi-Solver Comparison#
Recommendation: Pyomo
Rationale:
- 20+ solver backends (most flexible)
- Same model code across different solvers
- Extensive features (stochastic, disjunctive, DAE)
- Academic standard
Example: Comparing MILP solvers, testing problem formulations, operations research research
Scenario 9: Maximum MILP Performance#
Recommendation: Gurobi (direct API) or CPLEX (direct API)
Rationale:
- Fastest commercial solvers for large-scale MILP
- Direct API (gurobipy, docplex) avoids modeling language overhead
- Worth cost for time-critical, large-scale problems
Example: Large-scale logistics (100k+ variables), real-time optimization with tight deadlines
Scenario 10: Multi-Objective Optimization#
Recommendation: pymoo
Rationale:
- Only library specialized for multi-objective
- Generates Pareto frontier
- Modern evolutionary algorithms (NSGA-II, NSGA-III, MOEAD)
Example: Design optimization with competing objectives, trade-off analysis
Scenario 11: Dynamic Optimization / Optimal Control#
Recommendation: GEKKO or Pyomo.DAE
Rationale:
- GEKKO: Specialized for dynamic optimization, MPC, DAE systems
- Pyomo.DAE: Integrates with Pyomo ecosystem
Example: Process control, trajectory optimization, model predictive control
Scenario 12: Already Using SciPy/NumPy#
Recommendation: scipy.optimize (first), consider CVXPY if convex
Rationale:
- Zero additional dependencies
- Integrates with existing scipy/numpy code
- Good default for scientific computing workflows
Example: Scientific computing pipelines, data analysis notebooks
Library Comparison Matrix#
| Library | Problem Types | Difficulty | Solver Flexibility | Performance | Best For |
|---|---|---|---|---|---|
| scipy.optimize | LP, NLP | ⭐ Easy | ⭐ Low (HiGHS for LP only) | ⭐⭐ Good | Continuous, prototyping, scipy users |
| OR-Tools | LP, MILP, CP, VRP | ⭐⭐ Moderate | ⭐⭐ Medium (bundled) | ⭐⭐⭐ Excellent | Production, scheduling, routing |
| Pyomo | LP, MILP, NLP, MINLP | ⭐⭐ Moderate | ⭐⭐⭐ High (20+ solvers) | ⭐⭐ Good | Multi-solver research, complex models |
| CVXPY | Convex (LP, QP, SOCP, SDP) | ⭐⭐ Moderate | ⭐⭐ Medium | ⭐⭐⭐ Excellent | Convex optimization, ML, finance |
| PuLP | LP, MILP | ⭐ Easy | ⭐⭐ Medium | ⭐⭐ Good | Simple LP/MILP, learning |
| GEKKO | NLP, MINLP, DAE | ⭐⭐⭐ Advanced | ⭐⭐ Medium | ⭐⭐ Good | Dynamic optimization, MPC |
| pymoo | Multi-objective | ⭐⭐ Moderate | N/A | ⭐⭐ Good | Multi-objective, evolutionary |
Problem Type → Library Mapping#
| Problem Type | First Choice | Alternative | Commercial Option |
|---|---|---|---|
| LP | PuLP, scipy.optimize.linprog | Pyomo + HiGHS | Gurobi, CPLEX |
| MILP | PuLP, OR-Tools | Pyomo + CBC/SCIP | Gurobi, CPLEX |
| QP (convex) | CVXPY | Pyomo + Gurobi | Gurobi, MOSEK |
| NLP (small) | scipy.optimize | - | - |
| NLP (large) | Pyomo + IPOPT | GEKKO | KNITRO, SNOPT |
| MINLP | Pyomo + SCIP | GEKKO | BARON |
| Convex | CVXPY | - | MOSEK |
| CP | OR-Tools CP-SAT | - | - |
| Multi-objective | pymoo | - | - |
| Dynamic | GEKKO | Pyomo.DAE | - |
Solver Selection Guidance#
Open-Source Solvers (Free)#
Linear Programming:
- HiGHS: Rising star, adopted by SciPy and MATLAB. Fast, MIT license.
- GLPK: Mature, widely available. Slower than HiGHS.
- CLP: COIN-OR, good quality.
Mixed-Integer:
- SCIP: Fastest academic solver. Now Apache 2.0 (was academic-only).
- CBC: COIN-OR, bundled with PuLP. Solid performance.
- HiGHS: Also does MILP (not just LP).
Nonlinear:
- IPOPT: Interior point, large-scale. EPL license.
- Bonmin, Couenne: MINLP solvers. Academic use.
Constraint Programming:
- OR-Tools CP-SAT: Best-in-class. Apache 2.0.
Convex:
- Clarabel: Modern, Rust-based. Default in CVXPY.
- SCS: Robust, medium accuracy.
- OSQP: Fast for QP.
Commercial Solvers (Licensed)#
When to consider:
- Large-scale MILP (100k+ variables)
- Time-critical applications
- Maximum performance needed
- Budget available
Top choices:
- Gurobi: Fastest overall, excellent support, free for academics
- CPLEX: IBM, strong on high-dimensionality, free for academics
- MOSEK: Best for conic (SOCP, SDP), free for academics
Cost vs benefit: For small-medium problems, open-source competitive. For very large or time-critical, commercial worth cost.
Common Migration Paths#
1. Learning → Production#
Path: PuLP → OR-Tools or Pyomo + HiGHS
Rationale: Start simple with PuLP, graduate to production-grade tools as needs grow.
2. Prototype → Scale#
Path: scipy.optimize → Pyomo + IPOPT → Pyomo + commercial NLP solver
Rationale: Prototype with scipy, add algebraic modeling for complexity, scale to commercial for performance.
3. Open-Source → Commercial#
Path: Pyomo + CBC → Pyomo + Gurobi (same model code!)
Rationale: Develop with open-source, deploy with commercial for performance. Pyomo makes this seamless.
4. General → Specialized#
Path: Pyomo → CVXPY (if convex) or OR-Tools CP-SAT (if scheduling)
Rationale: Recognize problem structure, use specialized tool.
Anti-Recommendations#
❌ Don’t use scipy.optimize for:#
- Integer variables (no MILP support)
- Large-scale LP (use HiGHS via Pyomo or scipy.optimize.linprog)
❌ Don’t use PuLP for:#
- Nonlinear problems (no NLP support)
- Constraint programming (no CP support)
❌ Don’t use CVXPY for:#
- Non-convex problems (DCP will reject)
- Integer programming (limited support)
❌ Don’t use OR-Tools for:#
- Nonlinear programming (no NLP support)
- If algebraic modeling strongly preferred (Pyomo better)
❌ Don’t use Pyomo for:#
- Simple one-off problems (overhead not worth it)
- Constraint programming (OR-Tools CP-SAT better)
❌ Don’t use commercial solvers for:#
- Small problems (overkill)
- Budget-constrained projects (open-source competitive)
- Academic use without free license
Final Recommendations Summary#
Default Starting Points#
- LP/MILP: Start with PuLP (easiest)
- Convex: Use CVXPY (DCP verification)
- Continuous NLP: Use scipy.optimize (built-in)
- Scheduling: Use OR-Tools CP-SAT (best-in-class)
- Multi-objective: Use pymoo (specialized)
When to Graduate to More Powerful Tools#
- PuLP → Pyomo when need solver flexibility or complex models
- scipy.optimize → Pyomo + IPOPT when NLP gets large
- Open-source → Commercial when performance critical (Gurobi, CPLEX)
Production Deployments#
- OR-Tools: Safest choice (Google-backed, bundled solvers, proven)
- Pyomo + HiGHS/Gurobi: Strong alternative with solver flexibility
- CVXPY: If convex problems (finance, ML, control)
Academic Research#
- Pyomo: Standard for operations research (20+ solvers, extensive features)
- CVXPY: Standard for convex optimization (Stanford, widely cited)
- OR-Tools: For constraint programming research
Surprising Findings from Research#
HiGHS adoption: SciPy and MATLAB both chose HiGHS as default LP/MIP solver. Strong signal of quality.
SCIP now Apache 2.0: Previously academic-only, now fully open source. Major development for open-source MILP.
Gurobi/CPLEX withdrew from Mittelmann benchmarks: Reduces transparency. Open-source performance harder to compare.
OR-Tools CP-SAT dominance: Google’s CP-SAT wins MiniZinc Challenge medals, competitive with commercial CP solvers.
CVXPY’s DCP is unique: Only Python library with automatic convexity verification. Killer feature for convex problems.
Pyomo’s 20+ solvers: Far exceeds other modeling languages in flexibility.
PuLP’s simplicity: Still best entry point after 15+ years.
References#
This recommendation is based on:
- Library download statistics (PyPI, conda)
- GitHub metrics (stars, activity, contributors)
- Documentation quality assessment
- Academic publications (JMLR, IEEE Access, Nature Methods)
- Mittelmann benchmark analysis
- Community feedback (Stack Overflow, forums)
- Solver adoption patterns (SciPy, MATLAB)
Conclusion#
Problem type determines library choice. Once you know your problem type:
- LP/MILP: PuLP (simple) or OR-Tools/Pyomo (production)
- Convex: CVXPY
- NLP: scipy.optimize (small) or Pyomo (large)
- CP: OR-Tools CP-SAT
- Multi-objective: pymoo
Start with the simplest tool that fits your problem. Graduate to more powerful tools as needs grow. Pyomo provides migration path from open-source to commercial solvers with same model code.
The Python optimization ecosystem in 2025 is mature, with excellent open-source options competitive with commercial tools for many use cases.
scipy.optimize: Python’s Built-In Optimization#
Overview#
scipy.optimize is part of SciPy, the foundational scientific computing library for Python. It provides optimization algorithms for continuous problems, both constrained and unconstrained. Part of the scipy package which has millions of downloads per year (>13M from PyPI in 2019, likely much higher now as part of scientific Python stack).
Key insight: scipy.optimize is ubiquitous but limited to smaller-scale problems and lacks mixed-integer programming capability.
Installation#
pip install scipyscipy is typically pre-installed in scientific Python distributions (Anaconda, etc.) and has no external dependencies beyond NumPy.
Problem Types Supported#
| Problem Type | Supported | Notes |
|---|---|---|
| Unconstrained minimization | ✅ Yes | minimize with methods BFGS, Nelder-Mead, etc. |
| Bound-constrained | ✅ Yes | minimize with bounds parameter, L-BFGS-B |
| Linearly constrained | ✅ Yes | minimize with LinearConstraint |
| Nonlinearly constrained | ✅ Yes | minimize with NonlinearConstraint, SLSQP, trust-constr |
| Least-squares | ✅ Yes | least_squares (Levenberg-Marquardt, trust-region) |
| Curve fitting | ✅ Yes | curve_fit wrapper around least-squares |
| Root finding | ✅ Yes | root, fsolve |
| Linear programming | ✅ Yes | linprog (HiGHS backend since SciPy 1.6.0) |
| Integer variables | ❌ No | Cannot handle MILP |
| Global optimization | ⚠️ Limited | differential_evolution, basinhopping (metaheuristics) |
Basic Example: Unconstrained Optimization#
import numpy as np
from scipy.optimize import minimize
# Define Rosenbrock function (classic test problem)
def rosenbrock(x):
return sum(100.0 * (x[1:] - x[:-1]**2)**2 + (1 - x[:-1])**2)
# Initial guess
x0 = np.array([1.3, 0.7, 0.8, 1.9, 1.2])
# Optimize with BFGS (gradient-based)
result = minimize(rosenbrock, x0, method='BFGS')
print(f"Optimal solution: {result.x}")
print(f"Optimal value: {result.fun}")
print(f"Success: {result.success}")Basic Example: Constrained Optimization#
from scipy.optimize import minimize, LinearConstraint, NonlinearConstraint
# Minimize x^2 + y^2 subject to x + y >= 1, x >= 0, y >= 0
def objective(x):
return x[0]**2 + x[1]**2
# Linear constraint: x + y >= 1 → -x - y <= -1
linear_constraint = LinearConstraint([[1, 1]], [1], [np.inf])
# Bounds: x >= 0, y >= 0
bounds = [(0, None), (0, None)]
# Optimize with SLSQP (Sequential Least Squares Programming)
result = minimize(objective, x0=[0, 0], method='SLSQP',
constraints=linear_constraint, bounds=bounds)
print(f"Optimal solution: {result.x}") # Should be approximately [0.5, 0.5]
print(f"Optimal value: {result.fun}") # Should be approximately 0.5Basic Example: Linear Programming#
from scipy.optimize import linprog
# Minimize: c^T x
c = [-1, -2] # Coefficients (negative because linprog minimizes)
# Subject to: A_ub @ x <= b_ub
A_ub = [[2, 1], # 2x + y <= 20
[1, 2]] # x + 2y <= 20
b_ub = [20, 20]
# Bounds: x >= 0, y >= 0
bounds = [(0, None), (0, None)]
# Solve with HiGHS (default since SciPy 1.6.0)
result = linprog(c, A_ub=A_ub, b_ub=b_ub, bounds=bounds, method='highs')
print(f"Optimal solution: {result.x}")
print(f"Optimal value: {-result.fun}") # Negate because we minimized negativeAvailable Optimization Methods#
Unconstrained Minimization (minimize)#
| Method | Type | Derivatives | Characteristics |
|---|---|---|---|
'BFGS' | Quasi-Newton | First | Fast, requires gradient (auto-computed if not provided) |
'L-BFGS-B' | Quasi-Newton | First | Memory-efficient, handles bounds |
'Nelder-Mead' | Simplex | None | Derivative-free, robust but slower |
'Powell' | Direction set | None | Derivative-free |
'CG' | Conjugate gradient | First | Good for large problems |
'Newton-CG' | Newton | Second | Uses Hessian, very fast convergence |
'trust-constr' | Trust region | First/Second | Handles constraints, state-of-art |
Constrained Minimization#
| Method | Constraints | Derivatives | Notes |
|---|---|---|---|
'SLSQP' | Linear, nonlinear | First | Sequential Least Squares, mature |
'trust-constr' | Linear, nonlinear | First/Second | Modern, recommended for constrained |
'COBYLA' | Nonlinear | None | Derivative-free, slower |
Global Optimization#
| Function | Method | Notes |
|---|---|---|
differential_evolution | Genetic algorithm | Derivative-free, population-based |
basinhopping | Random + local | Combines global search with local refinement |
dual_annealing | Simulated annealing | Probabilistic global search |
shgo | Simplicial homology | Deterministic global search (convex problems) |
brute | Grid search | Exhaustive evaluation on grid |
Linear Programming#
| Method | Algorithm | Notes |
|---|---|---|
'highs' | Dual simplex, IPM | Default since 1.6.0, fastest |
'highs-ds' | Dual simplex | Simplex variant |
'highs-ipm' | Interior point | Interior point variant |
'interior-point' | Legacy IPM | Deprecated, use HiGHS |
'revised simplex' | Simplex | Deprecated, use HiGHS |
API Design Philosophy#
Functional interface: Pass objective function and constraints as Python functions. Solver calls them during optimization.
Advantages:
- Quick to get started
- Flexible (any Python code in objective)
- No need to learn modeling language
Disadvantages:
- No symbolic differentiation (relies on numerical gradients unless you provide analytical)
- Difficult to inspect or modify model structure
- Less efficient for large-scale problems
- Cannot export model to other solvers
Solver Backends#
scipy.optimize is both library and solver:
- Implements algorithms directly in Python/Cython (BFGS, Nelder-Mead, etc.)
- Wraps external solvers (HiGHS for LP since 1.6.0)
Cannot interface with external MILP or NLP solvers (Gurobi, CPLEX, IPOPT). For multi-solver support, use Pyomo or PuLP.
When to Use scipy.optimize#
✅ Good fit when:#
- Already using scipy/numpy: Zero additional dependencies
- Small to medium scale: Hundreds to thousands of variables
- Continuous variables: No integer decisions
- Rapid prototyping: Quick experiments, research code
- Function-based objective: Simulation output, machine learning model, complex calculation
- Scientific computing context: Parameter estimation, curve fitting, model calibration
❌ Not suitable when:#
- Integer variables required: No MILP capability → use PuLP, Pyomo, OR-Tools
- Large-scale LP/MILP: Thousands of constraints → use dedicated solvers
- Need solver flexibility: Cannot swap solvers (Gurobi vs CBC) → use Pyomo
- Complex model structure: Many constraints, reusable model → use algebraic modeling
- Production performance critical: Direct solver APIs (gurobipy) may be faster
Community and Maturity#
| Metric | Value/Status |
|---|---|
| Maturity | Mature (20+ years, scipy 0.x era) |
| Downloads | Millions (part of scipy package) |
| Maintenance | Very active (scipy core team) |
| Documentation | Excellent (scipy.org/docs) |
| License | BSD (permissive) |
| Python versions | 3.9+ (scipy 1.11+) |
scipy is the foundation of scientific Python. Extremely stable, well-tested, and maintained.
Key Findings from Research#
HiGHS adoption (2021): SciPy 1.6.0 switched to HiGHS for
linprog, providing competitive LP performance with open-source solver.No MILP support: This is the biggest limitation. For integer variables, must use other libraries.
Gradient computation: If you don’t provide analytical gradients, scipy uses finite differences (slow, inaccurate). Consider automatic differentiation (JAX, autograd).
Trust-region methods:
trust-constr(added 2018) is modern, robust method for constrained optimization. Recommended over older SLSQP for difficult problems.Global optimization limited: Metaheuristics (
differential_evolution) can escape local optima but no guarantee of global optimum. For convex problems, local methods sufficient.
Comparison with Alternatives#
| Feature | scipy.optimize | Pyomo | CVXPY | PuLP |
|---|---|---|---|---|
| Installation | Built-in (scipy) | pip install | pip install | pip install |
| MILP support | ❌ No | ✅ Yes | ❌ No | ✅ Yes |
| NLP support | ✅ Yes | ✅ Yes | ❌ No | ❌ No |
| Modeling style | Functional | Algebraic | Algebraic | Algebraic |
| Solver backends | Few (HiGHS for LP) | 20+ | 10+ | 10+ |
| Learning curve | Easy | Moderate | Moderate | Easy |
| Best for | Quick prototypes, NLP | Multi-solver flexibility | Convex optimization | Simple LP/MILP |
Example Use Cases (Generic)#
Parameter Estimation#
Fit model parameters to data by minimizing prediction error.
def model_prediction(params, inputs):
# Your model here
return predictions
def objective(params):
predictions = model_prediction(params, training_data)
return np.sum((predictions - observations)**2)
result = minimize(objective, initial_params, method='L-BFGS-B')Optimal Resource Allocation (Continuous)#
Allocate continuous quantities (e.g., budget, energy) across options to maximize utility.
def utility(allocation):
# Compute total utility from allocation
return -np.sum(utility_functions(allocation)) # Negative for minimization
constraints = {'type': 'eq', 'fun': lambda x: np.sum(x) - total_budget}
bounds = [(0, None)] * n_options
result = minimize(utility, initial_allocation, method='SLSQP',
constraints=constraints, bounds=bounds)Calibration Against Simulation#
Find input parameters that make simulation output match observed data.
def simulation_error(params):
# Run simulation with params
sim_output = run_simulation(params)
return np.sum((sim_output - target_output)**2)
result = minimize(simulation_error, initial_params, method='Nelder-Mead')References#
- SciPy documentation: https://docs.scipy.org/doc/scipy/reference/optimize.html
- SciPy 1.0 paper: Virtanen et al., Nature Methods 2020
- HiGHS integration: SciPy 1.6.0 release notes (2021)
Summary#
scipy.optimize is the default starting point for continuous optimization in Python. Excellent for:
- Research and prototyping
- Parameter estimation and curve fitting
- Small to medium problems
- Users already in scipy/numpy ecosystem
For production MILP, multi-solver support, or large-scale problems, consider Pyomo, PuLP, or OR-Tools instead.
S2: Comprehensive
S2-Comprehensive: Commercial vs Open-Source Solvers#
Performance Gap Analysis#
Historical Context (Pre-2024)#
Commercial solvers (Gurobi, CPLEX) were 5-10x faster than open-source on large MILP instances
Current Status (2025)#
Major shift: Gurobi and MindOpt withdrew from Mittelmann benchmarks (Aug/Dec 2024), reducing transparency
Open-Source Solvers#
HiGHS (MIT License)#
Adoption signal: Chosen as default LP/MIP solver by:
- SciPy 1.6.0+ (2021)
- MATLAB Optimization Toolbox
Performance: Competitive with commercial on LP, good on MILP Conclusion: Rising star, closing performance gap
SCIP (Apache 2.0, since v9.0)#
Status: Fastest academic MILP/MINLP solver Previous barrier: Academic-only license Now: Fully open-source (Apache 2.0) Performance: Competitive with commercial on many problems
IPOPT (EPL)#
Focus: Large-scale nonlinear programming Performance: Industry standard open-source NLP solver Limitation: Local optima only (non-convex problems)
CBC (EPL)#
Maturity: 15+ years Bundled: PuLP default Performance: 2-5x slower than SCIP, adequate for small-medium MILP
Commercial Solvers#
Gurobi#
Pricing: ~$10k-100k+/year (enterprise) Academic: Free Performance: Historically fastest MILP solver Benchmark status: Withdrew August 2024
CPLEX (IBM)#
Pricing: Similar to Gurobi Academic: Free Strengths: High-dimensionality problems, non-convex MIQP Benchmark status: Still participates
MOSEK#
Focus: Conic optimization (SOCP, SDP) Pricing: ~$5k-50k/year Academic: Free Assessment: Best commercial option for conic problems
KNITRO (Artelys)#
Focus: Nonlinear programming Performance: 2-10x faster than IPOPT on many NLP Pricing: $5k-50k/year
When Commercial Worth Cost#
Clear Justifications:#
- Very large MILP: 100k+ variables, 10k+ integer variables
- Time-critical production: Real-time optimization, tight SLAs
- ROI analysis: If optimization saves $100k+/year, $10k solver cost justified
- Professional support: Mission-critical applications need vendor support
Questionable:#
- Small-medium problems: Open-source competitive
- Research/exploration: Need flexibility more than maximum speed
- Budget constraints: $10k-100k is significant
Academic vs Industry Access#
Academic Advantages:#
- Free commercial licenses: Gurobi, CPLEX, MOSEK free for academic use
- Full functionality: No feature limitations
- Ideal for research: Test multiple solvers
Industry Reality:#
- Must pay: Commercial licenses expensive
- Open-source competitive: HiGHS, SCIP often sufficient
- Hybrid approach: Develop with open-source, deploy with commercial if needed
Cost Comparison#
| Solver | License | Annual Cost (Enterprise) | Academic |
|---|---|---|---|
| HiGHS | MIT | Free | Free |
| SCIP | Apache 2.0 | Free | Free |
| CBC | EPL | Free | Free |
| IPOPT | EPL | Free | Free |
| Gurobi | Commercial | $10k-100k+ | Free |
| CPLEX | Commercial | $10k-100k+ | Free |
| MOSEK | Commercial | $5k-50k | Free |
| KNITRO | Commercial | $5k-50k | Free |
Performance Tiers (Based on Historical Data)#
LP#
- Tier 1: HiGHS, Gurobi, CPLEX (gap narrowed)
- Tier 2: GLOP, CLP
- Tier 3: GLPK
MILP#
- Tier 1: Gurobi, CPLEX (historically)
- Tier 2: SCIP (best open-source)
- Tier 3: HiGHS, CBC
- Tier 4: GLPK
NLP#
- Tier 1: KNITRO, SNOPT
- Tier 2: IPOPT (excellent for open-source)
Convex Conic#
- Tier 1: MOSEK
- Tier 2: Clarabel, SCS, ECOS
Open-Source Advantages#
- Cost: Free (obviously)
- Transparency: Source code available
- Community: Active development, bug reporting
- Flexibility: Modify if needed
- No licensing: No license servers, floating licenses, compliance issues
Commercial Advantages#
- Performance: Still faster on largest instances
- Support: Professional support contracts
- Features: Advanced tuning, cloud, distributed solving
- Testing: Extensive QA, stability guarantees
Trend: Closing Gap#
Evidence:
- HiGHS adoption by SciPy, MATLAB
- SCIP now Apache 2.0 (removed licensing barrier)
- OR-Tools CP-SAT award-winning (beats commercial CP)
Implication: Open-source increasingly viable for production
Recommendations#
Start with Open-Source:#
- HiGHS (LP/MILP)
- SCIP (MILP/MINLP)
- IPOPT (NLP)
- OR-Tools (CP, routing)
- CVXPY with open solvers (convex)
Upgrade to Commercial When:#
- Profiling shows solver is bottleneck
- Problem size requires maximum performance
- Budget justifies cost (ROI positive)
- Professional support needed
Migration Path:#
Use Pyomo for seamless open-source → commercial migration:
# Development
solver = SolverFactory('scip')
# Production (same model code!)
solver = SolverFactory('gurobi')Licensing Considerations#
Open-Source Licenses:#
- MIT (HiGHS): Most permissive
- Apache 2.0 (SCIP, OR-Tools): Permissive, patent protection
- EPL (IPOPT, CBC): Weak copyleft
- GPL: Strong copyleft (few optimization solvers)
Commercial Licenses:#
- Named-user: Tied to individual
- Floating: Shared pool of licenses
- Cloud: Usage-based pricing
- Academic: Free but restricted to academic use
Key Findings#
- Open-source competitive for many use cases: No longer automatically commercial
- HiGHS emergence: Major development (SciPy, MATLAB adoption)
- SCIP Apache 2.0: Removes licensing barrier for best open-source MILP
- Benchmark withdrawal: Reduced transparency for commercial performance
- Commercial still faster on huge MILP: But gap narrowed
- CP-SAT excellence: OR-Tools competitive with commercial CP solvers
- Convex exception: MOSEK significantly faster than open-source for conic
Decision Framework#
Problem size and performance requirements?
├─ Small-medium → Open-source sufficient
│ └─ HiGHS, SCIP, IPOPT, OR-Tools
│
├─ Large, but not time-critical → Try open-source first
│ └─ Profile before deciding on commercial
│
└─ Very large AND time-critical → Commercial justified
└─ Gurobi, CPLEX (MILP), MOSEK (conic), Knitro (NLP)
Budget available?
├─ No → Open-source (HiGHS, SCIP excellent)
├─ Academic → Free commercial licenses available
└─ Industry → Evaluate ROI (does speed improvement justify cost?)Conclusion#
2025 landscape: Open-source solvers increasingly viable for production. Start with open-source; upgrade to commercial only when profiling demonstrates clear need. The performance gap has narrowed significantly, especially for LP and medium-scale MILP.
Biggest winners: HiGHS (LP/MILP), SCIP (MILP/MINLP), OR-Tools (CP), IPOPT (NLP)
Commercial still justified for: Very large MILP, professional support needs, conic optimization (MOSEK)
S2-Comprehensive: Modeling Languages vs Direct APIs#
Overview#
Optimization problems can be expressed through modeling languages (algebraic, declarative) or direct solver APIs (programmatic). Each approach has trade-offs.
Modeling Language Paradigm#
Concept#
Express optimization problems using mathematical notation similar to textbook formulations.
Examples#
- Pyomo: Python algebraic modeling
- CVXPY: Convex optimization modeling
- PuLP: Simple LP/MILP modeling
- AMPL, GAMS: Commercial modeling languages
- JuMP: Julia modeling language
Characteristics#
Algebraic syntax:
# Pyomo example
model = ConcreteModel()
model.x = Var(domain=NonNegativeReals)
model.y = Var(domain=NonNegativeReals)
model.obj = Objective(expr=model.x + 2*model.y, sense=maximize)
model.con1 = Constraint(expr=2*model.x + model.y <= 20)Advantages:
- Readable: Looks like mathematics
- Solver-agnostic: Change solver with one line
- Separation of model and data: Reusable structure
- Structured indexing: Sets, parameters, indexed variables
- Model introspection: Examine structure programmatically
- Educational: Clear formulation for teaching
Disadvantages:
- Learning curve: New syntax and concepts
- Performance overhead: 5-10% (typically)
- Abstraction layer: Less control over solver internals
- Installation: Modeling language + solver
When to Use#
- Complex models with many constraints
- Need solver flexibility
- Model reuse and maintenance
- Academic research
- Teaching optimization
Direct Solver API Paradigm#
Concept#
Call solver functions directly to build and solve models.
Examples#
- gurobipy: Gurobi Python API
- docplex: CPLEX Python API
- scipy.optimize: Function-based optimization
- OR-Tools: Object-oriented APIs
Characteristics#
Programmatic syntax:
# Gurobi direct API example
import gurobipy as gp
model = gp.Model()
x = model.addVar(name="x")
y = model.addVar(name="y")
model.setObjective(x + 2*y, gp.GRB.MAXIMIZE)
model.addConstr(2*x + y <= 20)
model.optimize()Advantages:
- Performance: Minimal overhead
- Fine control: Access solver-specific features
- Simpler installation: Just the solver
- Incremental building: Add/remove constraints efficiently
Disadvantages:
- Solver lock-in: Code tied to specific solver
- Less readable: More verbose than algebraic
- No solver abstraction: Can’t easily swap solvers
When to Use#
- Maximum performance needed
- Solver-specific features required
- Incremental model building (add/remove constraints frequently)
- Simple, one-off problems
- Production with fixed solver choice
Modeling Language Trade-offs#
Expressiveness vs Performance#
Algebraic modeling (Pyomo, CVXPY, PuLP):
- More expressive:
sum(x[i] for i in range(n)) - Slight overhead: Expression tree construction
Direct API (gurobipy, docplex):
- Less expressive: Must loop manually
- Minimal overhead: Direct solver calls
Overhead magnitude: 5-10% for large models (>10s solve time)
- For small models (
<1s), overhead can dominate - For large models, solver time dominates
Solver Flexibility#
Pyomo example: Same model, different solvers
# Try multiple solvers on same model
for solver_name in ['glpk', 'cbc', 'scip', 'gurobi']:
solver = SolverFactory(solver_name)
result = solver.solve(model)
print(f"{solver_name}: {value(model.obj)}")Direct API: Requires rewriting for each solver.
Model Maintenance#
Algebraic: Easy to modify structure
# Add new constraint to existing model
model.new_con = Constraint(expr=model.x + model.y >= 5)Direct API: More programmatic
# Gurobi: add constraint
model.addConstr(x + y >= 5)
model.update() # Some solvers require explicit updateHybrid Approaches#
Persistent Solvers (Pyomo)#
Best of both worlds for incremental modeling:
# Create model with Pyomo
model = ConcreteModel()
# ... define model ...
# Create persistent solver instance
solver = SolverFactory('gurobi', solver_io='python')
solver.set_instance(model)
# Solve
solver.solve()
# Modify model
model.new_con = Constraint(expr=model.x <= 10)
# Incremental resolve (fast!)
solver.solve() # Only communicates changesCVXPY Parameters#
Separate structure from data for fast re-solves:
# Define parameter (data that changes)
lambda_param = cp.Parameter(nonneg=True)
x = cp.Variable(n)
# Define problem once
objective = cp.Minimize(cp.sum_squares(A @ x - b) + lambda_param * cp.norm(x, 1))
problem = cp.Problem(objective, constraints)
# Solve for different lambda values (fast!)
for lam in [0.01, 0.1, 1.0]:
lambda_param.value = lam
problem.solve(warm_start=True)Comparison Matrix#
| Feature | Algebraic Modeling | Direct API | Hybrid |
|---|---|---|---|
| Readability | ⭐⭐⭐ High | ⭐⭐ Medium | ⭐⭐⭐ High |
| Performance | ⭐⭐ Good | ⭐⭐⭐ Excellent | ⭐⭐⭐ Excellent |
| Solver flexibility | ⭐⭐⭐ High | ⭐ Low | ⭐⭐ Medium |
| Learning curve | ⭐⭐ Moderate | ⭐⭐ Moderate | ⭐⭐⭐ Steep |
| Model maintenance | ⭐⭐⭐ Easy | ⭐⭐ Medium | ⭐⭐⭐ Easy |
| Incremental changes | ⭐ Slow | ⭐⭐⭐ Fast | ⭐⭐⭐ Fast |
Recommendations#
Use Algebraic Modeling When:#
- Model complexity justifies abstraction
- Solver experimentation needed
- Model will be reused/maintained
- Teaching or documentation important
- Not performance-critical
Use Direct API When:#
- Simple, one-off problem
- Maximum performance critical
- Solver-specific features needed
- Incremental model building
- Already committed to specific solver
Use Hybrid (Persistent/Parameters) When:#
- Need both flexibility and performance
- Many similar solves with parameter changes
- Production system with complex model
Comparison with OR-Tools#
OR-Tools uses module-specific APIs (different for LP, CP, routing):
Advantage: Specialized features for each problem type
Disadvantage: Less unified than pure algebraic modeling
Assessment: Good middle ground—more structured than raw API, more specialized than general algebraic modeling.
Migration Paths#
Prototype → Production#
- Prototype: Algebraic modeling (Pyomo, CVXPY, PuLP)
- Profile: Identify bottlenecks
- Optimize:
- Stay with algebraic if solver time dominates (common)
- Switch to persistent solvers if model building slow
- Switch to direct API only if profiling shows clear benefit
Open-Source → Commercial#
Pyomo shines here: Same model code, just change solver
# Development with open-source
solver = SolverFactory('cbc')
# Production with commercial (same model!)
solver = SolverFactory('gurobi')Key Takeaways#
- Algebraic modeling overhead small: 5-10% for large problems (solver dominates)
- Solver flexibility valuable: Pyomo’s 20+ solvers justify abstraction
- Direct API for performance critical: If profiling shows modeling overhead
- Hybrid approaches best of both: Persistent solvers, parameters
- Don’t optimize prematurely: Start with algebraic, profile before switching
- Problem size matters: Overhead negligible for
>10s solves, matters for<1s solves
Recommendation: Default to algebraic modeling (Pyomo, CVXPY, PuLP) unless profiling proves otherwise.
S2-Comprehensive: Solver Performance Comparison#
Overview#
Solver performance varies dramatically based on problem type, size, and structure. This document summarizes benchmark findings and performance characteristics.
Key Finding: Commercial Withdrawal from Public Benchmarks#
Major development (2024): Gurobi (August 2024) and MindOpt (December 2024) withdrew from Mittelmann benchmarks, reducing transparency in commercial vs open-source comparison.
Mittelmann Benchmarks#
Source: Hans Mittelmann, Arizona State University (plato.asu.edu/bench.html)
Coverage:
- Mixed-integer linear programming (MILP)
- Linear programming (LP)
- Network optimization
- Nonlinear programming (NLP)
- Semidefinite programming (SDP)
Interactive visualizations: mattmilten.github.io/mittelmann-plots (shows pairwise time comparisons)
Status (2025): Gurobi and MindOpt results removed. Remaining solvers: SCIP, HiGHS, CBC, GLPK, Xpress, others.
MILP Performance Tiers (Pre-Withdrawal Era)#
Tier 1: Premium Commercial#
Before withdrawal, Gurobi and CPLEX were:
- 5-10x faster than open-source on large instances
- Most consistent across problem classes
- Cost: $10k-100k+ annually (enterprise)
- Academic: Free
When justified:
- Large-scale instances (100k+ variables, 10k+ integer)
- Time-critical applications (real-time optimization)
- Mission-critical production systems
Tier 2: Open-Source Leaders#
SCIP (now Apache 2.0):
- Fastest open-source MILP solver
- Competitive with commercial on many problems
- Active development
HiGHS:
- Rising star (adopted by SciPy 1.6.0+, MATLAB)
- Excellent LP performance
- Good MILP performance
- MIT license, no dependencies
CBC (COIN-OR):
- Mature, stable
- Bundled with PuLP
- 2-5x slower than SCIP on average
- Good for small-medium problems
Tier 3: Basic Open-Source#
GLPK:
- Widely available
- Slower than CBC/SCIP/HiGHS
- Suitable for small problems (
<10k variables)
LP Performance#
HiGHS: Competitive with commercial solvers
- Chosen by SciPy and MATLAB as default LP solver
- Signal of high quality
GLOP (Google, in OR-Tools): Good performance for LP
Commercial (Gurobi, CPLEX): Still faster on very large instances, but gap narrowed significantly with HiGHS.
NLP Performance#
Open-Source#
IPOPT (Interior Point OPTimizer):
- Standard open-source NLP solver
- Large-scale capable (10k+ variables)
- Requires linear algebra libraries (HSL, MUMPS, Pardiso)
- Finds local optima (non-convex problems)
Commercial#
Knitro: Premium NLP solver (Artelys)
- Multiple algorithms (interior point, SQP, active set)
- Faster than IPOPT on many problems
- $5k-50k+ annually
SNOPT: Academic/commercial
- Sparse NLP
- Used in aerospace, engineering
Performance gap: Commercial 2-10x faster than IPOPT for large-scale NLP, but IPOPT excellent for open-source.
Convex Optimization Performance#
SOCP/SDP#
MOSEK: Commercial, best performance for conic problems
- Free for academic use
- Industry standard for SOCP/SDP
Open-source:
- SCS: Robust, medium accuracy
- ECOS: Good for small-medium SOCP
- Clarabel: Modern (Rust), becoming default in CVXPY
Performance: MOSEK 2-5x faster, but open-source sufficient for many applications.
Constraint Programming#
OR-Tools CP-SAT: Award-winning
- MiniZinc Challenge medals (2018, 2019, 2020, 2021)
- Competitive with commercial CP solvers
- Free, open-source (Apache 2.0)
Commercial CP:
- IBM CPLEX CP Optimizer
- Gecode
Performance: CP-SAT competitive, sometimes superior.
Problem Size Scaling#
LP#
- Small (
<1k variables): All solvers fast (<1second) - Medium (1k-100k): HiGHS, commercial excel
- Large (100k-1M+): Interior point methods (HiGHS, Gurobi, CPLEX) scale better than simplex
MILP#
- Small (
<100integer vars): All solvers acceptable - Medium (100-10k integer): SCIP, HiGHS, commercial
- Large (10k+ integer): Commercial formerly dominated (before withdrawal); SCIP best open-source
NLP#
- Small (
<100vars): scipy.optimize sufficient - Medium (100-10k): IPOPT, commercial
- Large (10k+): IPOPT, Knitro, SNOPT
Key insight: Problem size alone doesn’t determine hardness. Structure matters more (e.g., network flow LP with 1M variables easier than general MILP with 1k integer variables).
Formulation Impact on Performance#
Example: Same problem, different formulations can solve 10-1000x faster.
Tight formulation: LP relaxation close to integer hull
- Fewer branch-and-bound nodes
- Faster solve
Weak formulation: LP relaxation loose
- Many nodes explored
- Slow solve
Techniques to improve formulation:
- Disaggregation (break large constraints)
- Symmetry breaking (eliminate symmetric solutions)
- Valid inequalities (tighten relaxation)
- Alternative variable representations
Impact often exceeds solver choice: Well-formulated problem on CBC can solve faster than poorly-formulated on Gurobi.
Practical Performance Factors#
1. Presolve#
Modern solvers spend significant time in presolve:
- Can eliminate 50-90% of variables/constraints
- Sometimes solves problem entirely
- Usually worth the time
2. Warm Starting#
MILP: Providing known feasible solution speeds up solving NLP: Good initial guess critical for non-convex
3. Parallelization#
MILP: Scales well to 4-8 cores, diminishing returns beyond 16 NLP: Limited parallelization (inherently sequential)
4. Tolerances#
Relaxing optimality/feasibility tolerances (e.g., 1% vs 0.01%) can yield 10x speedup.
5. Time Limits#
For large MILP, setting time limit and accepting near-optimal solution often practical.
Benchmark Caveats#
- Problem-dependent: Solver rankings vary by problem class
- Version-dependent: Solvers improve continuously
- Tuning: Default parameters may not be optimal
- Hardware: Benchmark hardware may differ from yours
- Withdrawn solvers: Gurobi/CPLEX performance no longer publicly tracked
Python Library Overhead#
Modeling language overhead typically <10% of solve time for large problems.
Direct API vs modeling language:
- gurobipy (direct) slightly faster than Pyomo+Gurobi
- Matters for tiny problems (
<1s solve) or many sequential solves - For large problems (
>10s), solver dominates
Recommendation: Use algebraic modeling (Pyomo, CVXPY, PuLP) unless profiling shows bottleneck.
Performance Recommendations by Problem Type#
| Problem Type | Open-Source | Commercial | Comment |
|---|---|---|---|
| LP | HiGHS, GLOP | Gurobi, CPLEX | Gap narrowed significantly |
| MILP (small-medium) | SCIP, HiGHS, CBC | Gurobi, CPLEX | Open-source acceptable |
| MILP (large) | SCIP | Gurobi, CPLEX | Commercial faster (historically) |
| Convex QP | OSQP | Gurobi, MOSEK | Open-source good |
| NLP | IPOPT | Knitro, SNOPT | IPOPT very capable |
| SOCP/SDP | SCS, ECOS | MOSEK | MOSEK best |
| CP | OR-Tools CP-SAT | CPLEX CP | CP-SAT award-winning |
| Global MINLP | SCIP, Couenne | BARON | All slow (hard problem) |
When Commercial Solvers Worth the Cost#
- Very large MILP: 100k+ variables, 10k+ integer
- Time-critical: Real-time optimization, tight deadlines
- ROI justifies: If optimization saves $100k+, $10k solver cost trivial
- Support needed: Commercial provides professional support
When Open-Source Sufficient#
- Small-medium problems: Open-source competitive
- Budget constraints: Free vs $10k-100k
- Academic/research: Test multiple solvers
- HiGHS/SCIP for LP/MILP: Closing performance gap
Testing Methodology#
To compare solvers on YOUR problems:
import time
from pyomo.environ import *
def solve_with_solver(model, solver_name):
solver = SolverFactory(solver_name)
start = time.time()
result = solver.solve(model, tee=False)
elapsed = time.time() - start
return elapsed, result
# Test multiple solvers
for solver in ['glpk', 'cbc', 'scip', 'gurobi']:
elapsed, result = solve_with_solver(model, solver)
print(f"{solver}: {elapsed:.2f}s, obj={value(model.obj)}")Important: Test on YOUR problem instances, not just benchmarks.
Key Takeaways#
- HiGHS emergence: Major development in open-source landscape (SciPy, MATLAB adoption)
- SCIP now Apache 2.0: Eliminates licensing barrier for best open-source MILP
- CP-SAT excellence: OR-Tools CP-SAT world-class for scheduling
- Commercial gap varies: Large for giant MILP, small for LP/medium MILP
- Formulation matters more than solver: Good formulation on CBC > bad formulation on Gurobi
- Benchmark withdrawal reduces transparency: Harder to compare commercial vs open-source
References#
- Mittelmann Benchmarks: plato.asu.edu/bench.html
- Interactive visualizations: mattmilten.github.io/mittelmann-plots
- MIPLIB: miplib.zib.de (problem library)
- HiGHS paper: Huangfu & Hall, 2018
- SCIP Optimization Suite 9.0: Optimization Online 2024
S2-Comprehensive: Optimization Problem Types#
Overview#
Optimization problems are classified by the mathematical structure of the objective function, constraints, and variables. This classification determines which algorithms can solve the problem and computational complexity.
Key principle: Problem structure determines solvability. Linear problems are polynomial-time; integer programming is NP-hard; general nonlinear can be intractable.
Taxonomy of Optimization Problems#
Optimization Problems
│
├── Continuous Variables Only
│ ├── Unconstrained
│ │ ├── Convex → Global optimum guaranteed
│ │ └── Non-convex → Local optima exist
│ │
│ └── Constrained
│ ├── Linear Programming (LP)
│ │ └── Polynomial-time solvable (simplex, interior point)
│ │
│ ├── Convex Optimization
│ │ ├── Quadratic Programming (QP)
│ │ ├── Second-Order Cone Programming (SOCP)
│ │ ├── Semidefinite Programming (SDP)
│ │ └── General Convex → Local = Global optimum
│ │
│ └── Nonlinear Programming (NLP)
│ ├── Convex → Efficient algorithms
│ └── Non-convex → Difficult, local optima
│
└── Discrete/Integer Variables
├── Integer Linear Programming (ILP)
│ └── NP-hard
│
├── Mixed-Integer Linear (MILP)
│ └── NP-hard, but practical algorithms effective
│
├── Mixed-Integer Nonlinear (MINLP)
│ └── Very difficult
│
├── Constraint Programming (CP)
│ └── Logical constraints, domain propagation
│
└── Combinatorial Optimization
└── Graph problems, scheduling, routing1. Linear Programming (LP)#
Definition#
Optimize a linear objective function subject to linear equality and inequality constraints:
minimize c^T x
subject to Ax ≤ b
Aeq x = beq
lb ≤ x ≤ ubWhere:
x ∈ ℝⁿ: Decision variables (continuous)c: Cost coefficientsA, b: Inequality constraintsAeq, beq: Equality constraintslb, ub: Variable bounds
Mathematical Properties#
- Convex feasible region: Defined by linear constraints (polyhedron)
- Convex objective: Linear function is convex
- Optimal solution: Occurs at a vertex of the feasible polyhedron
- Fundamental theorem: If optimal solution exists, at least one vertex is optimal
Algorithms#
Simplex Method: Walk along edges of feasible region from vertex to vertex
- Average-case polynomial, worst-case exponential
- Very effective in practice
Interior Point Methods: Move through interior of feasible region
- Polynomial-time in theory and practice
- Better for large-scale problems
Dual Simplex: Operates on dual problem
- Useful when starting from infeasible solution
Complexity#
Polynomial-time solvable in practice. While simplex has worst-case exponential complexity, interior point methods are polynomial, and simplex is extremely effective on practical instances.
Standard Forms#
Inequality form (shown above)
Standard form: All constraints are equalities with non-negative variables
minimize c^T x
subject to Ax = b
x ≥ 0Conversion: Add slack variables to convert inequalities to equalities.
Special Cases#
Network Flow Problems: LP with network structure
- Min-cost flow, max-flow, shortest path
- Special algorithms exploit structure (network simplex)
- Integer optimal solutions possible with integer data
Transportation Problem: Ship goods from sources to destinations
- Bipartite network flow
- Degenerate structure common
Assignment Problem: Assign tasks to workers
- Special case of transportation
- Hungarian algorithm (combinatorial)
Applications (Generic)#
- Resource allocation with linear costs
- Production planning (continuous quantities)
- Diet/nutrition optimization
- Financial portfolio (without risk minimization)
- Network flow and routing (continuous)
- Blending problems
Python Libraries#
- scipy.optimize.linprog: HiGHS backend, good for small-medium
- PuLP: Algebraic modeling, CBC bundled
- Pyomo: Multi-solver support
- OR-Tools: GLOP solver (Google)
- CVXPY: Convex optimization framework
2. Mixed-Integer Linear Programming (MILP/MIP)#
Definition#
Linear programming where some or all variables must take integer values:
minimize c^T x
subject to Ax ≤ b
x_i ∈ ℤ for i ∈ I (integer variables)
x_j ∈ ℝ for j ∈ C (continuous variables)
x_i ∈ {0,1} for i ∈ B (binary variables)Mathematical Properties#
- NP-hard: No known polynomial-time algorithm
- Combinatorial: Integer variables create discrete decision space
- Feasible region: Union of polyhedra (non-convex)
- Non-convex: Linear combination of feasible points may be infeasible
Algorithms#
Branch-and-Bound:
- Solve LP relaxation (remove integer constraints)
- Branch on fractional variables
- Bound: LP relaxation provides lower bound (minimization)
- Prune branches that cannot improve incumbent solution
Branch-and-Cut:
- Branch-and-bound + cutting planes
- Generate inequalities (cuts) that tighten LP relaxation
- Cuts remove fractional solutions without removing integer solutions
- Modern solvers (Gurobi, CPLEX, SCIP) use sophisticated cuts
Branch-and-Price:
- Column generation within branch-and-bound
- For problems with huge numbers of variables
- Generate variables as needed
Cutting Planes#
Inequalities added to strengthen LP relaxation:
- Gomory cuts: General integer cuts
- Lift-and-project: Nonlinear inequalities projected to linear
- Cover cuts: For knapsack constraints
- Clique cuts: For conflict graphs
- MIR (Mixed-Integer Rounding): For mixed-integer problems
Formulation Quality#
Strong formulation: LP relaxation tight (close to convex hull of integer solutions)
Weak formulation: LP relaxation loose (far from integer hull)
Impact: Strong formulations solve much faster. Reformulation techniques:
- Disaggregation
- Symmetry breaking
- Tighter constraints
- Auxiliary variables
Complexity#
- NP-hard in general
- Practical solvability: Modern solvers (Gurobi, CPLEX, SCIP) solve instances with millions of variables and tens of thousands of integer variables
- Problem-dependent: Some structures solve easily (network flow), others intractable
Special Cases#
- Pure Integer Programming (ILP): All variables integer
- Binary Programming: All variables binary (0/1)
- Set Covering/Packing/Partitioning: Binary variables, specialized structure
Applications (Generic)#
- Facility location (open/close decisions)
- Production planning (batch sizes, setup decisions)
- Scheduling (discrete time periods, binary assignments)
- Routing (visit/don’t visit decisions)
- Portfolio selection with cardinality constraints
- Cutting stock and bin packing
- Network design (select edges to include)
Python Libraries#
- PuLP: Simple, CBC bundled
- Pyomo: Multi-solver (CBC, SCIP, Gurobi, CPLEX)
- OR-Tools: SCIP bundled, excellent
- Gurobi (gurobipy): Commercial, fastest
- CPLEX (docplex): IBM commercial
3. Quadratic Programming (QP)#
Definition#
Quadratic objective, linear constraints:
minimize (1/2) x^T Q x + c^T x
subject to Ax ≤ b
Aeq x = beqConvex vs Non-Convex#
Convex QP: Q is positive semidefinite (Q ⪰ 0)
- Local optimum is global
- Polynomial-time solvable
- Interior point methods effective
Non-Convex QP: Q has negative eigenvalues
- Local optima exist
- NP-hard in general
- Much harder to solve
Algorithms#
Convex QP:
- Interior point methods (primal-dual)
- Active set methods
- Augmented Lagrangian
Non-Convex QP:
- Branch-and-bound (spatial branching)
- SDP relaxations
- Local solvers (may find local optima)
Applications#
- Portfolio optimization (minimize variance)
- Support Vector Machines (SVM)
- Least-squares problems with constraints
- Model Predictive Control (MPC)
- Robust optimization
Python Libraries#
- CVXPY: If convex (automatic verification)
- Pyomo + Gurobi/CPLEX: Commercial solvers handle QP
- scipy.optimize.minimize: For small convex QP
- OSQP: Specialized convex QP solver (via CVXPY)
4. Second-Order Cone Programming (SOCP)#
Definition#
Optimization with second-order cone (norm) constraints:
minimize c^T x
subject to ||A_i x + b_i||_2 ≤ c_i^T x + d_i for all i
Fx = gThe constraint ||A_i x + b_i||_2 ≤ c_i^T x + d_i defines a second-order cone (also called Lorentz cone or ice cream cone).
Properties#
- Convex: Second-order cone is convex
- Generalizes QP and LP: LP (no cones), QP (single quadratic cone)
- Interior point methods: Polynomial-time solvable
Applications#
- Robust optimization (worst-case constraints)
- Portfolio optimization with Value-at-Risk (VaR)
- Antenna array design
- Filter design in signal processing
- Structural optimization (engineering)
Python Libraries#
- CVXPY: Natural SOCP modeling with
cp.norm - Pyomo + MOSEK: Commercial solver strong on SOCP
- SCS, ECOS: Open-source conic solvers (via CVXPY)
5. Semidefinite Programming (SDP)#
Definition#
Optimization with positive semidefinite matrix constraints:
minimize Trace(CX)
subject to Trace(A_i X) = b_i
X ⪰ 0 (positive semidefinite)Where X is a matrix variable, and X ⪰ 0 means all eigenvalues of X are non-negative.
Properties#
- Convex: Positive semidefinite cone is convex
- Generalizes LP and SOCP: LP (diagonal X), SOCP (special structure)
- Computationally expensive: Scales poorly with matrix size
Applications#
- Combinatorial optimization relaxations
- Control theory (Lyapunov stability, LQR)
- Matrix completion problems
- Max-cut relaxation
- Quantum information theory
Python Libraries#
- CVXPY:
cp.Variable((n, n), PSD=True)for SDP variables - MOSEK: Commercial, best SDP performance
- SCS: Open-source conic solver
6. Nonlinear Programming (NLP)#
Definition#
General nonlinear objective or constraints:
minimize f(x)
subject to g_i(x) ≤ 0
h_j(x) = 0Where f, g_i, h_j are nonlinear functions.
Convex vs Non-Convex#
Convex NLP: f convex, g_i convex, h_j affine
- Local optimum is global
- Efficient algorithms
- Interior point, SQP methods
Non-Convex NLP: General case
- Multiple local optima
- No guarantee of global optimum
- Sensitive to initialization
- Much harder
Algorithms#
Sequential Quadratic Programming (SQP):
- Solve sequence of QP subproblems
- Approximate objective and constraints with quadratic models
- Very effective for smooth constrained NLP
Interior Point Methods:
- Barrier methods (penalize constraint violations)
- IPOPT (Interior Point OPTimizer) widely used
Augmented Lagrangian:
- Penalty methods with Lagrange multipliers
- Robust to poor initialization
Trust Region Methods:
- Limit step size to region where model is trusted
- Adapt trust region based on model accuracy
Derivatives#
Most NLP algorithms require:
- First derivatives (gradient of objective, Jacobian of constraints)
- Second derivatives (Hessian) for faster convergence
Automatic differentiation: Compute exact derivatives algorithmically (not finite differences)
Complexity#
- Convex: Polynomial-time solvable (similar to LP)
- Non-convex: Can be very difficult, no general guarantees
Applications#
- Engineering design optimization (structural, aerodynamic)
- Chemical process optimization (nonlinear kinetics, thermodynamics)
- Parameter estimation (fit nonlinear models to data)
- Optimal control (continuous time, nonlinear dynamics)
- Machine learning (neural networks via gradient descent)
Python Libraries#
- scipy.optimize: Good for small-medium NLP (SLSQP, trust-constr)
- Pyomo + IPOPT: Large-scale NLP, open-source
- Pyomo + SNOPT/KNITRO: Commercial NLP solvers
- GEKKO: Dynamic optimization and NLP
7. Mixed-Integer Nonlinear Programming (MINLP)#
Definition#
Nonlinear objective or constraints with integer variables:
minimize f(x, y)
subject to g_i(x, y) ≤ 0
h_j(x, y) = 0
x ∈ ℝⁿ
y ∈ ℤᵐDifficulty#
Very hard: Combines difficulty of MILP (NP-hard) and NLP (local optima, non-convexity).
Algorithms#
- Branch-and-Bound: Solve NLP relaxations
- Outer Approximation: Linearize nonlinear constraints
- Generalized Benders Decomposition: Decompose into MILP master and NLP subproblem
- Hybrid methods: Combine multiple techniques
Solvers#
- BARON: Global MINLP solver (deterministic)
- SCIP: Open-source (now Apache 2.0)
- Couenne, Bonmin: Open-source (EPL)
- ANTIGONE: Academic
- Pyomo.MindtPy: Decomposition-based MINLP
Applications#
- Process synthesis (select equipment + optimize operating conditions)
- Network design with nonlinear flows
- Discrete optimization with nonlinear physics
8. Constraint Programming (CP)#
Definition#
Solve problems with logical and combinatorial constraints using:
- Domain propagation
- Constraint inference
- Backtracking search
Characteristics#
- Declarative: Specify what constraints must hold
- Logical constraints: All-different, precedence, no-overlap, cumulative
- Finite domains: Variables take values from finite sets
- Different paradigm: Not mathematical programming
Algorithms#
- Domain Propagation: Remove values inconsistent with constraints
- Constraint Propagation: Infer new constraints from existing
- Backtracking Search: Try variable assignments, backtrack if infeasible
Applications#
- Job shop scheduling
- Employee rostering and timetabling
- Resource-constrained project scheduling
- Configuration problems
- Puzzles (Sudoku, N-queens)
Python Libraries#
- OR-Tools CP-SAT: Best-in-class, MiniZinc Challenge winner
- python-constraint: Simple CP library
- Gecode (via Python bindings): Academic CP solver
9. Multi-Objective Optimization#
Definition#
Multiple objective functions to optimize simultaneously:
minimize [f_1(x), f_2(x), ..., f_k(x)]
subject to g_i(x) ≤ 0Pareto Optimality#
Pareto optimal: Solution where improving one objective worsens another.
Pareto frontier: Set of all Pareto optimal solutions.
Approaches#
Weighted Sum: Minimize
Σ w_i f_i(x)for weightsw_i- Simple, but cannot find non-convex parts of Pareto frontier
Epsilon-Constraint: Optimize one objective, constrain others
- Can find entire Pareto frontier
Evolutionary Algorithms: Generate population covering Pareto frontier
- NSGA-II, NSGA-III, MOEAD (in pymoo)
Applications#
- Design optimization (cost vs performance vs weight)
- Portfolio optimization (return vs risk vs liquidity)
- Environmental planning (cost vs emissions vs reliability)
- Engineering trade-offs
Python Libraries#
- pymoo: Specialized multi-objective library (NSGA-II, NSGA-III)
- Pyomo + epsilon-constraint: Manual implementation
- CVXPY + weighted sum: If convex
10. Stochastic Programming#
Definition#
Optimization under uncertainty where uncertain parameters have known probability distributions.
Two-Stage Formulation#
minimize c^T x + E[Q(x, ξ)]
subject to Ax = b
x ≥ 0Where:
- First stage: Decisions
xmade before uncertainty revealed - Second stage: Recourse decisions after observing random outcome
ξ - Q(x, ξ): Optimal value of second-stage problem given
xandξ
Solution Methods#
- Sample Average Approximation (SAA): Sample scenarios, solve large deterministic problem
- L-shaped method: Benders decomposition for two-stage
- Progressive hedging: Decomposition by scenario
Python Libraries#
- Pyomo.PySP: Stochastic programming extension (deprecated in favor of mpi-sppy)
- mpi-sppy: Modern stochastic programming in Pyomo
11. Robust Optimization#
Definition#
Optimize for worst-case performance over uncertain parameters (no probability distribution assumed).
minimize max_{u ∈ U} f(x, u)
subject to g_i(x, u) ≤ 0 for all u ∈ UWhere U is uncertainty set (e.g., box, ellipsoid, polyhedron).
Approaches#
- Worst-case: Optimize for worst scenario in uncertainty set
- Robust counterpart: Reformulate as deterministic problem
- Affine adaptation: Decision rules linear in uncertainty
Python Libraries#
- CVXPY: Modeling robust constraints with norms
- Pyomo: Manual reformulation
12. Dynamic Optimization / Optimal Control#
Definition#
Optimize decisions over time subject to dynamic system equations (differential or difference equations).
Continuous time:
minimize ∫ L(x(t), u(t)) dt
subject to dx/dt = f(x(t), u(t))
x(0) = x_0Discrete time:
minimize Σ L_t(x_t, u_t)
subject to x_{t+1} = f_t(x_t, u_t)Methods#
- Direct Methods: Discretize time, solve large NLP
- Indirect Methods: Solve optimality conditions (Pontryagin maximum principle)
- Dynamic Programming: Bellman equation (limited to low dimensions)
- Model Predictive Control (MPC): Solve finite-horizon repeatedly
Python Libraries#
- GEKKO: Specialized for dynamic optimization, DAE, MPC
- Pyomo.DAE: Differential-algebraic equation extension
- CasADi (via Python): Optimal control and NLP
Problem Type Selection Guide#
Decision Questions#
Are variables continuous or discrete?
- Continuous → LP, QP, NLP, convex
- Discrete → MILP, CP, combinatorial
- Mixed → MILP, MINLP
Is objective/constraint nonlinear?
- No (all linear) → LP or MILP
- Yes (nonlinear) → NLP, QP, convex, or MINLP
If nonlinear, is problem convex?
- Yes (convex) → Convex optimization (efficient!)
- No (non-convex) → General NLP (harder)
- Don’t know → Test with CVXPY (DCP analysis)
Are there logical constraints?
- Yes (all-different, no-overlap, etc.) → CP
- No → Mathematical programming
Multiple objectives?
- Yes → Multi-objective optimization
- No → Single-objective
Dynamic system over time?
- Yes → Dynamic optimization, optimal control
- No → Static optimization
Uncertainty?
- Stochastic (known distributions) → Stochastic programming
- Robust (worst-case) → Robust optimization
- None → Deterministic
Complexity Hierarchy#
Easy ← ────────────────────────────────────────────────────────── → Hard
LP → Convex QP → Convex NLP → MILP → Non-convex NLP → MINLP
│ │
└─ Polynomial-time └─ NP-hardKey insight: Convexity and linearity enable efficient solving. Integer variables and non-convexity add difficulty.
Summary#
| Problem Type | Variables | Objective | Constraints | Complexity | Algorithms |
|---|---|---|---|---|---|
| LP | Continuous | Linear | Linear | Polynomial | Simplex, Interior point |
| MILP | Integer + Continuous | Linear | Linear | NP-hard | Branch-and-bound, cuts |
| QP | Continuous | Quadratic | Linear | Poly (convex), NP-hard (general) | Interior point, active set |
| SOCP | Continuous | Linear | SOC | Polynomial | Interior point |
| SDP | Matrix (PSD) | Linear | Linear + PSD | Polynomial (slow) | Interior point |
| NLP | Continuous | Nonlinear | Nonlinear | Poly (convex), Hard (general) | SQP, Interior point |
| MINLP | Integer + Continuous | Nonlinear | Nonlinear | Very hard | Branch-and-bound, decomp |
| CP | Discrete | Any | Logical | NP-hard | Propagation, search |
Problem type determines tool selection. Identify your problem type first, then choose appropriate library and solver.
S2-Comprehensive: Solver Algorithms#
Overview#
Optimization solvers implement algorithms that compute optimal solutions. Understanding algorithm categories helps select appropriate solvers and diagnose performance issues.
Algorithm Categories by Problem Type#
1. Linear Programming Algorithms#
Simplex Method#
Invented: George Dantzig, 1947
Principle: Walk along edges of feasible polyhedron from vertex to vertex, always improving objective.
Steps:
- Start at feasible vertex
- Identify improving edge (reduced cost < 0)
- Move to adjacent vertex along edge
- Repeat until no improving edges exist
Complexity:
- Worst-case: Exponential (Klee-Minty cube)
- Average-case: Polynomial (empirically)
- Practical performance: Excellent
Variants:
- Primal simplex
- Dual simplex (maintains dual feasibility)
- Revised simplex (matrix form, more efficient)
- Network simplex (specialized for network problems)
Solvers: GLPK, CLP, GLOP (Google), Gurobi, CPLEX
Interior Point Methods#
Invented: Karmarkar, 1984 (modern version)
Principle: Move through interior of feasible region toward optimum.
Steps:
- Start at interior point
- Follow central path (points equally far from boundaries)
- Apply barrier method to penalize boundary violations
- Converge to optimum on boundary
Complexity: Polynomial-time (theory and practice)
Advantages:
- Guaranteed polynomial time
- Better for large-scale problems
- Parallelizable
Disadvantages:
- More complex implementation
- Does not exploit warm starts as well as simplex
Solvers: IPOPT (nonlinear), Gurobi, CPLEX, MOSEK, HiGHS
When to use:
- Large-scale LP (100k+ variables)
- When polynomial-time guarantee matters
- Problems without warm start
2. Mixed-Integer Programming Algorithms#
Branch-and-Bound#
Principle: Systematically enumerate solution space using bounds to prune.
Steps:
- Solve LP relaxation (remove integer constraints) → lower bound
- If solution integer, update incumbent (best known)
- If fractional, branch: create two subproblems
- Subproblem 1: Add constraint
x_i ≤ ⌊x_i*⌋ - Subproblem 2: Add constraint
x_i ≥ ⌈x_i*⌉
- Subproblem 1: Add constraint
- Prune branches where bound ≥ incumbent
- Repeat until all branches explored or pruned
Tree structure:
LP relaxation (3.7, 2.3) → obj = 15.2
/ \
x ≤ 3 x ≥ 4
(3, 2.6) (4, 1.8)
obj = 14.8 obj = 15.5 (prune if incumbent < 15.5)Node selection strategies:
- Depth-first: Quickly find feasible solutions
- Best-bound: Prove optimality faster
- Hybrid: Modern solvers use sophisticated strategies
Variable selection: Which fractional variable to branch on?
- Most fractional
- Pseudocost branching (estimate impact)
- Strong branching (tentatively solve subproblems)
Cutting Planes#
Principle: Add linear inequalities (cuts) that eliminate fractional solutions without removing integer solutions.
Types of cuts:
- Gomory cuts: General integer cuts from simplex tableau
- Cover cuts: For knapsack constraints
- Clique cuts: From conflict graphs
- MIR (Mixed-Integer Rounding): For mixed-integer constraints
- Lift-and-project: Strengthen constraints
- Problem-specific: Exploit special structure
Example: For x₁ + x₂ ≤ 1.5 with x₁, x₂ binary, LP relaxation allows x₁ = x₂ = 0.75. Cut x₁ + x₂ ≤ 1 eliminates this fractional solution.
Branch-and-Cut#
Modern standard: Combine branch-and-bound with cutting planes.
Process:
- Solve LP relaxation
- Generate cuts to strengthen relaxation
- Branch if still fractional
- Apply cuts at each node
Modern solvers: Gurobi, CPLEX, SCIP use sophisticated branch-and-cut with:
- Automatic cut generation
- Primal heuristics (find feasible solutions quickly)
- Parallelization
- Presolve (problem reduction)
Presolve#
Principle: Simplify problem before solving.
Techniques:
- Remove redundant constraints
- Fix variables (if bounds imply fixed value)
- Tighten bounds
- Detect special structure
- Aggregate variables
- Dual reductions
Impact: Can reduce problem size dramatically, sometimes solving problem in presolve.
3. Nonlinear Programming Algorithms#
Gradient-Based Methods#
Gradient Descent:
x_{k+1} = x_k - α_k ∇f(x_k)Move in direction of steepest descent. Simple but slow convergence.
Newton’s Method:
x_{k+1} = x_k - [∇²f(x_k)]⁻¹ ∇f(x_k)Use second derivatives (Hessian) for quadratic convergence. Expensive per iteration.
Quasi-Newton (BFGS, L-BFGS): Approximate Hessian from gradient history. Balance of speed and accuracy.
- BFGS: Full Hessian approximation
- L-BFGS: Limited-memory variant (for large-scale)
Advantages: Fast convergence for smooth problems
Requirements: First derivatives (gradients), optionally second derivatives
Sequential Quadratic Programming (SQP)#
Principle: Solve sequence of quadratic programming subproblems.
Steps:
- Approximate objective and constraints with quadratic/linear models
- Solve QP subproblem for search direction
- Line search along direction
- Update approximations
- Repeat until convergence
Performance: Very effective for smooth constrained NLP
Solvers: SNOPT, NLPQL, scipy.optimize (SLSQP)
Interior Point Methods (Barrier Methods)#
Principle: Penalize constraint violations with barrier function.
Barrier function: f(x) + μ Σ -log(g_i(x))
As μ → 0, barrier pushes solution toward feasible region boundary.
Advantages:
- Handles inequality constraints naturally
- Good for large-scale problems
- Polynomial-time for convex problems
Solvers: IPOPT, Knitro
Trust Region Methods#
Principle: Limit step size to region where quadratic model is trusted.
Steps:
- Build quadratic model of objective around current point
- Solve for step within trust region (radius Δ)
- Evaluate actual improvement vs predicted
- If good agreement, accept step and expand trust region
- If poor agreement, reject step and shrink trust region
Advantages: Robust to poor initialization, handles non-smooth regions
Solvers: scipy.optimize (trust-constr), TAO
4. Derivative-Free Optimization#
Use case: Objective function is black-box, non-smooth, or noisy (e.g., simulation output).
Nelder-Mead Simplex#
Principle: Geometric search using simplex (n+1 points in n dimensions).
Operations:
- Reflection: Mirror worst point through centroid
- Expansion: Extend if reflection improves
- Contraction: Shrink if reflection fails
- Shrink: Contract entire simplex
Advantages: Robust, no derivatives needed
Disadvantages: Slow, can stall, no convergence guarantees
Powell’s Method#
Principle: Sequential line searches along conjugate directions.
Advantages: More efficient than Nelder-Mead for smooth problems
Pattern Search#
Principle: Evaluate at geometric patterns around current point.
Mesh adaptive direct search (MADS): Theoretical convergence guarantees.
5. Metaheuristics#
Use case: Global optimization, non-convex problems, combinatorial problems.
Genetic Algorithms#
Principle: Evolutionary process with selection, crossover, mutation.
Steps:
- Initialize population
- Evaluate fitness
- Select parents (roulette wheel, tournament)
- Crossover (combine parent genes)
- Mutation (random changes)
- Replace population
- Repeat for generations
Advantages: Global search, handles non-convex, no derivatives
Disadvantages: Many evaluations, no optimality guarantee
Simulated Annealing#
Principle: Probabilistically accept worse solutions to escape local optima.
Temperature schedule: Start hot (accept most moves), cool down (become greedy).
Metropolis criterion: Accept worse solution with probability exp(-ΔE/T)
Particle Swarm Optimization#
Principle: Particles explore space influenced by personal best and swarm best.
Update rule:
v_{i,t+1} = w·v_{i,t} + c₁·r₁·(p_i - x_{i,t}) + c₂·r₂·(g - x_{i,t})
x_{i,t+1} = x_{i,t} + v_{i,t+1}Where:
v_i: Velocity of particle ip_i: Personal best of particle ig: Global best of swarmw, c₁, c₂: Parametersr₁, r₂: Random numbers
Advantages: Simple, effective for many problems
Python library: pymoo, scipy.optimize.differential_evolution
6. Constraint Programming Algorithms#
Domain Propagation#
Principle: Remove values from variable domains that cannot satisfy constraints.
Arc consistency: For constraint between x and y, remove values from x’s domain that have no supporting value in y’s domain.
Example: x + y = 10, x ∈ {1,2,3}, y ∈ {7,8,9}
After propagation: x ∈ {1,2,3}, y ∈ {7,8,9} (already consistent)
If x ∈ {1,2}, y ∈ {7,8,9,10} → propagate → y ∈ {8,9} (x=1→y=9, x=2→y=8)
Backtracking Search#
Principle: Assign variables sequentially, backtrack when conflict detected.
With constraint propagation: Propagate after each assignment to detect conflicts early.
Heuristics:
- Variable ordering: Which variable to assign next? (most constrained first)
- Value ordering: Which value to try? (least constraining first)
CP-SAT (OR-Tools)#
Modern CP solver using Boolean satisfiability (SAT) techniques:
- Encode constraints as Boolean formulas
- Use advanced SAT solver techniques
- Combine with LP relaxation for optimization
Performance: Award-winning (MiniZinc Challenge medals)
Algorithm Selection by Problem Type#
| Problem Type | Primary Algorithm | Solvers |
|---|---|---|
| LP | Simplex or Interior Point | HiGHS, GLPK, CLP, Gurobi, CPLEX |
| MILP | Branch-and-Cut | CBC, SCIP, HiGHS, Gurobi, CPLEX |
| Convex QP | Interior Point | OSQP, MOSEK, Gurobi, CPLEX |
| Convex NLP | Interior Point, SQP | IPOPT, Knitro, SNOPT |
| Non-convex NLP | SQP, Trust Region, Multi-start | IPOPT (local), BARON (global) |
| MINLP | Branch-and-Bound + NLP | SCIP, BARON, Bonmin, Couenne |
| CP | Domain Propagation + Search | OR-Tools CP-SAT, Gecode |
| Global non-convex | Metaheuristics, Branch-and-Bound | Genetic algorithms, BARON |
Modern Solver Enhancements#
Parallelization#
- Branch-and-bound: Solve multiple nodes concurrently
- Portfolio approaches: Try multiple strategies in parallel
- Multi-threading: Modern solvers (Gurobi, CPLEX) use 8-16 cores effectively
Machine Learning in Solvers#
- Branching heuristics: Learn variable selection from problem history
- Cut selection: Learn which cuts are effective
- Node selection: Learn promising branches
- Warm starting: Transfer solutions across similar problems
Automatic Tuning#
- Parameter tuning: Solvers have 100+ parameters
- Gurobi Tuning Tool: Automatically find best parameter settings for problem class
Algorithmic Complexity Summary#
| Algorithm | Worst-Case | Average-Case | Practical |
|---|---|---|---|
| Simplex | Exponential | Polynomial | Excellent |
| Interior Point | Polynomial | Polynomial | Very good |
| Branch-and-Bound | Exponential | Varies | Good with cuts |
| SQP | N/A (iterative) | Superlinear | Excellent (smooth NLP) |
| IPOPT | Polynomial (convex) | Varies | Very good |
| Genetic Algorithms | N/A | N/A | Depends on problem |
Key Insights#
Simplex vs Interior Point: Simplex better for small-medium LP, interior point for large-scale. Simplex exploits warm starts better.
Cuts are critical for MILP: Modern MILP performance comes from sophisticated cutting plane generation, not just branch-and-bound.
Convexity enables efficiency: Convex problems have polynomial-time algorithms. Non-convex may require global optimization methods.
Derivatives matter: Gradient-based NLP algorithms much faster than derivative-free for smooth problems. Use automatic differentiation.
Presolve can be transformative: Sometimes reduces problem to trivial size.
Metaheuristics don’t guarantee optimality: But useful for hard non-convex problems where local methods fail.
CP excels at scheduling: Domain propagation very effective for combinatorial structure (no-overlap, all-different).
Algorithm choice impacts performance 10-1000x: Choosing right algorithm/solver for problem type is critical.
References#
- Nocedal & Wright, “Numerical Optimization” (2006)
- Wolsey, “Integer Programming” (2020)
- Boyd & Vandenberghe, “Convex Optimization” (2004)
- Biegler, “Nonlinear Programming” (2010)
S3: Need-Driven
S3-Need-Driven: Decision Framework#
Overview#
Practical decision framework for selecting Python optimization tools.
Step-by-Step Selection Process#
Step 1: Identify Problem Type#
Questions to ask:
- Are variables continuous or discrete (integer)?
- Is objective function linear or nonlinear?
- Are constraints linear or nonlinear?
- Do you need multiple objectives?
- Are there logical constraints (scheduling, all-different)?
Decision tree: See S1-rapid/approach.md for detailed problem type taxonomy
Output: Problem type (LP, MILP, NLP, MINLP, convex, CP, multi-objective)
Step 2: Assess Problem Size#
Small: <1000 variables, <100 constraints
Medium: 1k-100k variables, 100-10k constraints
Large: >100k variables, >10k constraints
Why it matters: Some libraries/solvers better for large scale
Step 3: Determine Priorities#
Rank these priorities:
- Simplicity: Easy to learn and use
- Solver flexibility: Try multiple solvers
- Performance: Maximum speed
- Cost: Budget constraints
- Production readiness: Stability, support
Step 4: Apply Selection Matrix#
| Problem Type | Priority: Simplicity | Priority: Flexibility | Priority: Performance | Priority: Cost |
|---|---|---|---|---|
| LP | PuLP | Pyomo | HiGHS (via any) | HiGHS (free) |
| MILP | PuLP | Pyomo | Gurobi* | SCIP (free) |
| NLP | scipy.optimize | Pyomo | Knitro* | IPOPT (free) |
| Convex | CVXPY | CVXPY | MOSEK* | CVXPY+SCS |
| CP/Scheduling | OR-Tools | OR-Tools | OR-Tools | OR-Tools (free) |
| Multi-obj | pymoo | pymoo | pymoo | pymoo (free) |
*Commercial solver (free academic, paid industry)
Scenario-Based Recommendations#
Scenario 1: Data Scientist, Prototype LP/MILP#
Profile: Python fluent, occasional optimization, proof-of-concept Recommendation: PuLP Rationale: Simplest learning curve, CBC bundled, adequate performance
Scenario 2: Operations Researcher, Multiple Solver Experiments#
Profile: Academic research, need to compare solvers Recommendation: Pyomo Rationale: 20+ solver backends, academic standard, excellent docs
Scenario 3: Software Engineer, Production Scheduling System#
Profile: Building production service, scheduling core Recommendation: OR-Tools CP-SAT Rationale: Production-ready, award-winning CP solver, Google-backed, bundled
Scenario 4: Quant Finance, Portfolio Optimization#
Profile: Financial applications, convex optimization Recommendation: CVXPY Rationale: DCP verification, designed for finance/ML, Stanford origins
Scenario 5: Process Engineer, Nonlinear Process Optimization#
Profile: Chemical/mechanical engineering, nonlinear physics Recommendation: Pyomo + IPOPT (or GEKKO if dynamic) Rationale: Nonlinear support, IPOPT industry standard open-source, GEKKO for DAE
Scenario 6: Logistics Company, Large-Scale Routing#
Profile: Real-world logistics, vehicle routing with constraints Recommendation: OR-Tools routing module Rationale: Specialized VRP solvers, time windows support, production-proven
Scenario 7: ML Researcher, Hyperparameter Tuning#
Profile: Machine learning, optimize hyperparameters Recommendation: Optuna (not general optimization library!) Rationale: Specialized for hyperparameter optimization, TPE algorithm
Scenario 8: Startup, Large MILP, Limited Budget#
Profile: Cost-sensitive, need good MILP performance Recommendation: Pyomo + SCIP Rationale: SCIP now Apache 2.0 (free), best open-source MILP, Pyomo flexibility
Scenario 9: Enterprise, Mission-Critical, Budget Available#
Profile: Large company, optimization-critical, can afford commercial Recommendation: Pyomo + Gurobi or direct Gurobi API Rationale: Maximum performance, professional support, Pyomo enables open-source dev
Scenario 10: Student, Learning Optimization#
Profile: Learning, want to try everything, limited budget Recommendation: Start PuLP, then Pyomo (with academic Gurobi if available) Rationale: Easy start, graduate to flexibility, free academic licenses
Migration Decision Framework#
When to Stay with Current Tool#
- Meets performance requirements
- Team fluent in tool
- No significant pain points
- Cost of migration > benefit
When to Migrate#
- Performance bottleneck (solver, not formulation)
- Need capabilities current tool lacks (e.g., MILP when using scipy.optimize)
- Open-source → commercial justified by ROI
- Simpler tool available (over-using complex tool for simple problem)
How to Migrate#
Pyomo makes this easy:
# Development
solver = SolverFactory('cbc') # Open-source
# Production (same model!)
solver = SolverFactory('gurobi') # CommercialOtherwise: Rewrite model in new library (cost of migration)
Red Flags (Don’t Select If…)#
| Library | Don’t Select If… |
|---|---|
| scipy.optimize | Need integer variables, large-scale LP |
| PuLP | Need nonlinear, constraint programming |
| Pyomo | Simple one-off problem (overhead not worth it) |
| CVXPY | Problem is non-convex (DCP will reject) |
| OR-Tools | Need nonlinear programming |
| GEKKO | Not working with dynamic systems |
| pymoo | Single-objective problem |
| Commercial solver | Small problem, limited budget, open-source sufficient |
Decision Checklist#
Before finalizing decision, verify:
- Problem type correctly identified (LP, MILP, NLP, etc.)
- Library supports problem type
- Solver availability (free/commercial, license compliance)
- Team can learn library (documentation, examples available)
- Performance adequate for problem size
- Budget allows (commercial solvers $10k-100k/year)
- Integration with existing codebase feasible
- Community support available (Stack Overflow, GitHub)
Quick Reference Card#
Need to solve NOW, minimal research:
- LP/MILP: Use PuLP
- Continuous NLP: Use scipy.optimize
- Convex: Use CVXPY
- Scheduling: Use OR-Tools CP-SAT
- Multi-objective: Use pymoo
Have time to learn, want best tool:
- Read S1-rapid/recommendation.md
- Apply this decision framework
- Test on small instance before committing
Key Principle#
Problem type determines library, not domain. Scheduling is scheduling whether it’s manufacturing, healthcare, or transportation. Selection criteria are problem structure, not industry.
Final Recommendation#
Default path for most users:
- Start with PuLP (LP/MILP) or scipy.optimize (NLP)
- Graduate to Pyomo when complexity justifies (or need solver flexibility)
- Use specialists (CVXPY, OR-Tools, pymoo) for their domains
- Consider commercial (Gurobi) only when open-source performance insufficient
This path minimizes learning curve while providing upgrade path as needs grow.
S3-Need-Driven: Learning Curve Assessment#
Overview#
Learning curve estimates based on documentation quality, community resources, and complexity.
Learning Curve Rankings#
Easy (1-2 days to productive)#
PuLP: Simplest LP/MILP modeling
- Minimal concepts: LpProblem, LpVariable, constraints
- Pythonic syntax
- Excellent tutorials
scipy.optimize (basic): Continuous optimization
- Functional interface (pass functions)
- Part of scipy (familiar to scientists)
- Good documentation
Moderate (1 week to productive)#
Pyomo: Algebraic modeling
- New syntax (ConcreteModel, Var, Objective, Constraint)
- Set-based indexing concept
- Solver installation required
- Excellent docs and textbook
CVXPY: Convex optimization
- DCP rules learning curve
- Need to understand convexity
- Good documentation and examples
OR-Tools: Multiple modules
- Different APIs for LP, CP, routing
- Good Google developer docs
- Many examples
Advanced (2-4 weeks to productive)#
GEKKO: Dynamic optimization
- Dynamic optimization concepts (DAE, MPC)
- Specialized domain
- Good tutorials but smaller community
pymoo: Multi-objective optimization
- Evolutionary algorithm concepts
- Multi-objective theory (Pareto frontier)
- IEEE paper + docs
Learning Resources by Library#
scipy.optimize#
Official docs: ⭐⭐⭐⭐⭐ Excellent
- https://docs.scipy.org/doc/scipy/reference/optimize.html
- Clear API reference
- Many examples
Tutorials: ⭐⭐⭐⭐ Good
- Real Python tutorials
- Stack Overflow coverage
Community: ⭐⭐⭐⭐⭐ Huge (scipy ecosystem)
PuLP#
Official docs: ⭐⭐⭐⭐ Good
- https://coin-or.github.io/pulp/
- Case studies
- Clear examples
Tutorials: ⭐⭐⭐ Adequate
- Medium articles
- University course materials
Community: ⭐⭐⭐ Good
Pyomo#
Official docs: ⭐⭐⭐⭐⭐ Excellent
- https://pyomo.readthedocs.io
- Comprehensive
- API reference + conceptual
Book: “Pyomo — Optimization Modeling in Python” (Springer)
Tutorials: ⭐⭐⭐⭐⭐ Excellent
- University courses use Pyomo
- Many academic examples
Community: ⭐⭐⭐⭐ Strong (academic)
CVXPY#
Official docs: ⭐⭐⭐⭐⭐ Excellent
- https://www.cvxpy.org
- Tutorial, examples, API reference
- DCP rules explained
Academic paper: JMLR 2016
Tutorials: ⭐⭐⭐⭐⭐ Excellent
- Stanford CVX101 course
- Many examples
Community: ⭐⭐⭐⭐ Strong (academic + industry)
OR-Tools#
Official docs: ⭐⭐⭐⭐⭐ Excellent
- https://developers.google.com/optimization
- Google-quality docs
- Many examples for each module
Tutorials: ⭐⭐⭐⭐ Good
- Routing tutorial excellent
- CP-SAT examples
Community: ⭐⭐⭐⭐ Good (Google + community)
GEKKO#
Official docs: ⭐⭐⭐ Adequate
- https://gekko.readthedocs.io
- Focus on examples
Tutorials: ⭐⭐⭐ Good
- APMonitor tutorials (BYU)
- Specialized for dynamic optimization
Community: ⭐⭐ Small (niche domain)
pymoo#
Official docs: ⭐⭐⭐⭐ Good
- https://pymoo.org
- Algorithms documented
- Getting started guides
Academic paper: IEEE Access 2020
Community: ⭐⭐⭐ Growing
Common Learning Challenges#
Challenge 1: Problem Type Identification#
Difficulty: Moderate Solution: Use decision trees in this research (S1-rapid/approach.md)
Challenge 2: Mathematical Formulation#
Difficulty: Hard (requires optimization knowledge) Solution: Start with generic patterns (S3-need-driven/use-cases.md), adapt
Challenge 3: Solver Installation#
Difficulty: Variable
- Easy: PuLP (CBC bundled), OR-Tools (bundled), scipy (built-in)
- Moderate: Pyomo (install GLPK, CBC separately)
- Hard: IPOPT (requires linear algebra libraries)
Challenge 4: Debugging Infeasibility#
Difficulty: Hard Tips:
- Start with small test instances
- Remove constraints incrementally
- Check constraint units and scales
- Use solver diagnostics (IIS - Irreducible Infeasible Set)
Challenge 5: Performance Tuning#
Difficulty: Advanced Requires: Understanding of algorithms, formulation quality
Recommended Learning Paths#
Path 1: Beginner (LP/MILP)#
- Week 1: PuLP basics (simple LP)
- Week 2: PuLP + integer variables (MILP)
- Week 3: Graduate to Pyomo for complex models
- Week 4: Experiment with solvers (CBC, SCIP, commercial if available)
Path 2: Scientific Computing Background#
- Week 1: scipy.optimize (unconstrained, then constrained)
- Week 2: CVXPY (if working with convex problems)
- Week 3: Pyomo (when need MILP or multi-solver)
Path 3: Scheduling/Combinatorial#
- Week 1: Basic MILP with PuLP
- Week 2: OR-Tools CP-SAT
- Week 3: Advanced CP-SAT features
- Week 4: Routing module if needed
Path 4: Nonlinear/Dynamic#
- Week 1-2: scipy.optimize (NLP basics)
- Week 3-4: Pyomo + IPOPT
- Week 5+: GEKKO for dynamic optimization
Time to First Working Model#
| Library | Simple Problem | Complex Problem |
|---|---|---|
| PuLP | 30 min | 2-4 hours |
| scipy.optimize | 15 min | 1-2 hours |
| Pyomo | 1-2 hours | 4-8 hours |
| CVXPY | 1 hour | 3-5 hours |
| OR-Tools | 1-2 hours | 4-8 hours |
| GEKKO | 2-3 hours | 1-2 days |
(Assumes familiarity with Python and optimization concepts)
Success Factors#
Accelerate Learning:#
- Start with examples: Modify existing code before writing from scratch
- Small test instances: Debug on tiny problems
- One concept at a time: Don’t combine learning optimization + new domain + new library
- Community: Stack Overflow, GitHub issues
- Documentation quality: Pyomo, CVXPY, OR-Tools have excellent docs
Common Mistakes:#
- Wrong problem type: Using MILP tools for NLP, or vice versa
- Scaling issues: Variables differ by orders of magnitude
- Infeasibility: Over-constrained problem
- Performance expectations: Not all problems solvable quickly
- Premature optimization: Worry about formulation before solving
Key Takeaways#
- PuLP easiest entry point for LP/MILP
- scipy.optimize easiest for continuous problems
- Documentation quality matters: Pyomo, CVXPY, OR-Tools shine
- Generic patterns accelerate learning: Adapt examples from use-cases.md
- Community support varies: scipy, Pyomo, CVXPY have strong communities
- Time investment: 1 week to productivity for most libraries (moderate problems)
S3-Need-Driven: Simulation-Optimization Coupling#
Overview#
Coupling optimization with simulation (from research/1.120-simulation) enables optimizing systems too complex for closed-form models.
When to Couple Simulation + Optimization#
Use When:#
- Objective function cannot be written analytically
- Complex stochastic processes
- System dynamics require detailed simulation
- What-if analysis insufficient (need optimal decisions)
Don’t Use When:#
- Objective can be modeled directly (LP, MILP, NLP)
- Simulation too slow for many evaluations
- Can approximate with simpler model
Coupling Approaches#
1. Simulation-Based Optimization (Metaheuristics)#
Pattern: Simulation evaluates objective, metaheuristic searches
def objective(params):
# Run simulation with params
results = run_simulation(params, n_replications=30)
return np.mean(results['cost'])
# Optimize using derivative-free method
result = scipy.optimize.minimize(objective, x0, method='Nelder-Mead')Suitable algorithms:
- Genetic algorithms (pymoo)
- Simulated annealing
- Particle swarm
- Nelder-Mead, Powell (scipy.optimize)
Challenge: Each objective evaluation expensive (simulation run)
2. Simulation + Mathematical Programming#
Pattern: Use simulation output as input to optimization
Example: Supply chain optimization
- Simulate demand uncertainty → estimate demand distributions
- Solve MILP for inventory/production decisions given demand
- Validate decisions with simulation
3. Metamodel-Based Optimization#
Pattern: Build surrogate model from simulation, optimize surrogate
Steps:
- Sample parameter space (Latin hypercube, design of experiments)
- Run simulations at sample points
- Fit metamodel (polynomial, kriging, neural network)
- Optimize metamodel (fast!)
- Validate at optimal point with full simulation
Advantage: Separate expensive simulation from optimization
4. Iterative Optimization-Simulation#
Pattern: Alternate between optimization and simulation validation
Steps:
- Solve optimization with simplified model
- Validate solution with detailed simulation
- Update model based on simulation results
- Re-optimize
- Repeat until convergence
Integration Patterns#
Pattern 1: Parameters → Simulation → Performance#
Optimize control parameters:
# Example: Inventory policy optimization
def evaluate_policy(reorder_point, order_quantity):
sim_results = run_inventory_simulation(reorder_point, order_quantity, n_days=365)
return sim_results['total_cost']
# Find best policy parameters
result = minimize(lambda p: evaluate_policy(p[0], p[1]), x0=[50, 100])Pattern 2: Simulation → Data → Optimization#
Use simulation to generate scenarios:
# Generate demand scenarios via simulation
scenarios = [simulate_demand() for _ in range(100)]
# Solve stochastic optimization with scenarios
model = ConcreteModel()
# ... define variables ...
for s, scenario in enumerate(scenarios):
# Add constraints for this scenario
model.add_component(f'demand_con_{s}',
Constraint(expr=model.production >= scenario['demand']))Key Considerations#
Computational Budget#
- Each simulation run costs time
- Limit optimization to
<1000evaluations typically - Use efficient optimization algorithms (few evaluations)
Stochasticity#
- Simulation outputs are random
- Multiple replications needed for accuracy
- Statistical comparison of solutions
Validation#
- Validate optimal solution with independent simulation runs
- Check robustness to parameter variations
Tools and Libraries#
| Approach | Python Library | Notes |
|---|---|---|
| Metaheuristics | pymoo, scipy.optimize.differential_evolution | For black-box objectives |
| Gradient-free NLP | scipy.optimize (Nelder-Mead, Powell) | Small parameter spaces |
| Metamodeling | scikit-learn, GPy (Gaussian processes) | Build surrogates |
| MP + Simulation | Pyomo, PuLP (optimization) + SimPy, Ciw (simulation) | Separate tools |
Example: Queueing System Optimization#
Problem: Find staffing levels minimizing cost + wait time
Simulation: SimPy model of queueing system Optimization: Minimize cost function evaluated by simulation
def simulate_queue(n_servers):
# Run SimPy simulation
results = run_simpy_model(n_servers, sim_time=1000)
avg_wait = results['avg_wait_time']
cost = n_servers * server_cost + avg_wait * wait_penalty
return cost
# Discrete optimization (integer servers)
best_cost = float('inf')
best_servers = None
for n in range(1, 20):
cost = simulate_queue(n)
if cost < best_cost:
best_cost = cost
best_servers = nReferences#
- Fu, M.C. (2002). “Optimization for Simulation: Theory vs. Practice”. INFORMS J. on Computing.
- Law, A.M. (2015). “Simulation Modeling and Analysis” (Chapter on optimization)
- Research 1.120 (Simulation libraries in this repository)
Key Takeaways#
- Use when objective can’t be modeled directly
- Computational cost is main constraint
- Derivative-free methods required (black-box objective)
- Metamodeling reduces evaluations
- Validate optimal solution with independent runs
S3-Need-Driven: Generic Use Case Patterns#
Overview#
Optimization use cases organized by problem pattern, not industry. These patterns are application-neutral and reusable.
1. Resource Allocation#
Pattern#
Allocate limited resources across competing options to maximize total value.
Mathematical Structure#
- Variables: Allocation amounts (continuous or discrete)
- Objective: Maximize total value or minimize total cost
- Constraints: Resource limits, minimum/maximum allocations
Problem Types#
- Continuous allocation: LP
- Discrete allocation: MILP
- With diminishing returns: Convex optimization (QP)
Generic Examples#
- Budget allocation across projects
- Computing capacity allocation across workloads
- Storage space allocation across tenants
- Energy allocation across production units
- Personnel allocation across tasks
Modeling Pattern#
# Pyomo example
model = ConcreteModel()
model.OPTIONS = Set(initialize=options)
model.allocate = Var(model.OPTIONS, domain=NonNegativeReals)
model.obj = Objective(expr=sum(value[o] * model.allocate[o] for o in model.OPTIONS), sense=maximize)
model.capacity = Constraint(expr=sum(model.allocate[o] for o in model.OPTIONS) <= total_capacity)2. Scheduling with Constraints#
Pattern#
Schedule tasks over time subject to precedence, resource limits, and time windows.
Mathematical Structure#
- Variables: Start/end times, binary assignment variables
- Objective: Minimize makespan, minimize tardiness, maximize throughput
- Constraints: Precedence (A before B), resource capacity, time windows, no-overlap
Problem Types#
- Discrete time: MILP
- Continuous time: NLP or CP
- With logical constraints: Constraint Programming (CP)
Generic Examples#
- Job shop scheduling (tasks on machines)
- Project scheduling with dependencies
- Appointment scheduling with availability windows
- Batch production scheduling
- Maintenance scheduling with downtime constraints
Modeling Approach#
Constraint Programming (OR-Tools CP-SAT) often best for scheduling due to:
- Natural expression of logical constraints (no-overlap, all-different)
- Domain propagation effectiveness
- Award-winning performance
# OR-Tools CP-SAT example
from ortools.sat.python import cp_model
model = cp_model.CpModel()
# Interval variables for tasks
intervals = []
for task in tasks:
start = model.NewIntVar(0, horizon, f'start_{task}')
duration = durations[task]
end = model.NewIntVar(0, horizon, f'end_{task}')
interval = model.NewIntervalVar(start, duration, end, f'interval_{task}')
intervals.append(interval)
# No-overlap constraint
model.AddNoOverlap(intervals)
# Minimize makespan
makespan = model.NewIntVar(0, horizon, 'makespan')
for interval in intervals:
model.Add(makespan >= interval.EndExpr())
model.Minimize(makespan)3. Selection and Assignment#
Pattern#
Select subset of items or assign items to slots, optimizing total value subject to constraints.
Mathematical Structure#
- Variables: Binary (selected/not, assigned/not)
- Objective: Maximize value or minimize cost
- Constraints: Cardinality (select exactly K), capacity, exclusion, dependency
Problem Types#
- Binary selection: MILP
- Assignment with matching: MILP (assignment problem)
Generic Examples#
- Project portfolio selection with budget
- Facility location (which facilities to open)
- Supplier selection in procurement
- Feature selection in product design
- Worker-task assignment
- Knapsack problems (packing with value)
Modeling Pattern#
# Binary selection
model.select = Var(ITEMS, domain=Binary)
model.obj = Objective(expr=sum(value[i] * model.select[i] for i in ITEMS), sense=maximize)
model.budget = Constraint(expr=sum(cost[i] * model.select[i] for i in ITEMS) <= budget_limit)
# Cardinality: select exactly K items
model.cardinality = Constraint(expr=sum(model.select[i] for i in ITEMS) == K)4. Network Flow and Routing#
Pattern#
Route flow through network minimizing cost or maximizing throughput.
Mathematical Structure#
- Variables: Flow on each arc
- Objective: Minimize cost or maximize flow
- Constraints: Flow conservation (inflow = outflow), capacity limits
Problem Types#
- Continuous flow: LP (network simplex)
- Discrete routing: MILP
- Vehicle routing: Specialized algorithms (OR-Tools routing)
Generic Examples#
- Supply chain network (factory → warehouse → customer)
- Transportation routing (minimize distance/cost)
- Communication network routing (maximize throughput)
- Pipeline flow optimization
- Logistics network design
Modeling Advantage#
Network flow problems have special structure enabling very efficient solution (network simplex faster than general LP).
# Min-cost flow (OR-Tools)
from ortools.graph import pywrapgraph
min_cost_flow = pywrapgraph.SimpleMinCostFlow()
for (source, dest, capacity, cost) in arcs:
min_cost_flow.AddArcWithCapacityAndUnitCost(source, dest, capacity, cost)
# Supply/demand at nodes
for node, supply in supplies.items():
min_cost_flow.SetNodeSupply(node, supply)5. Cutting and Packing#
Pattern#
Cut raw materials into required pieces minimizing waste, or pack items into containers minimizing containers used.
Mathematical Structure#
- Variables: Pattern usage (how many times each cutting/packing pattern used)
- Objective: Minimize waste or minimize containers
- Constraints: Meet demand for each item size
Problem Types#
- 1D cutting stock: Column generation (LP/MILP)
- 2D/3D bin packing: MILP (very hard)
Generic Examples#
- Cutting steel rolls into required widths
- Cutting fabric into pattern pieces
- Packing boxes into shipping containers
- Packing advertisements into pages
- Memory allocation in computing
Algorithmic Approach#
Column generation: Generate cutting patterns on-the-fly rather than enumerate all upfront.
6. Blending and Mixing#
Pattern#
Mix inputs to meet output specifications at minimum cost.
Mathematical Structure#
- Variables: Quantity of each input
- Objective: Minimize total cost
- Constraints: Meet requirements for output properties (nutrients, strength, etc.)
Problem Types#
- Linear blending: LP
- With nonlinear properties: NLP
Generic Examples#
- Feed/nutrition blending (meet nutrient requirements)
- Chemical blending (meet specification)
- Fuel blending (octane rating, emissions)
- Alloy blending (metal composition)
- Portfolio blending (risk/return characteristics)
7. Portfolio Optimization#
Pattern#
Select combination of assets balancing risk and return.
Mathematical Structure#
- Variables: Portfolio weights (allocation to each asset)
- Objective: Minimize risk (variance) or maximize return
- Constraints: Total weight = 1, minimum return target, diversification limits
Problem Types#
- Mean-variance: Quadratic programming (QP)
- With constraints: Convex optimization (CVXPY)
- With cardinality limits: MILP (select K of N assets)
Generic Example#
# CVXPY portfolio optimization
w = cp.Variable(n_assets) # Portfolio weights
risk = cp.quad_form(w, cov_matrix)
objective = cp.Minimize(risk)
constraints = [
cp.sum(w) == 1, # Weights sum to 1
w >= 0, # No short selling
returns @ w >= target # Meet return target
]
problem = cp.Problem(objective, constraints)8. Parameter Estimation and Calibration#
Pattern#
Find model parameters that best fit observed data.
Mathematical Structure#
- Variables: Model parameters
- Objective: Minimize prediction error (least-squares, maximum likelihood)
- Constraints: Parameter bounds, physical constraints
Problem Types#
- Linear regression: LP or QP
- Nonlinear regression: NLP
- With regularization: Convex optimization (Lasso, ridge)
Generic Examples#
- Calibrate simulation parameters to match real system
- Fit demand model to historical data
- Estimate failure rates from field data
- Calibrate financial model to market data
Modeling Pattern#
# scipy.optimize for calibration
def simulation_error(params):
predictions = run_simulation(params)
return np.sum((predictions - observations)**2)
result = minimize(simulation_error, initial_params, bounds=param_bounds)9. Multi-Objective Trade-off Analysis#
Pattern#
Optimize multiple competing objectives simultaneously.
Mathematical Structure#
- Variables: Design or decision variables
- Objectives: Multiple objective functions (e.g., cost, performance, quality)
- Output: Pareto frontier (set of non-dominated solutions)
Problem Types#
- Multi-objective optimization: Evolutionary algorithms (pymoo)
- Convex multi-objective: Weighted sum or epsilon-constraint
Generic Examples#
- Product design: minimize cost, maximize quality, minimize weight
- System design: maximize performance, minimize energy, minimize cost
- Policy design: maximize effectiveness, minimize cost, minimize risk
Approach#
# pymoo for multi-objective
from pymoo.algorithms.moo.nsga2 import NSGA2
from pymoo.optimize import minimize
# Define problem with multiple objectives
problem = MyMultiObjectiveProblem()
algorithm = NSGA2(pop_size=100)
result = minimize(problem, algorithm, ('n_gen', 200))
# Result contains Pareto frontier
pareto_front = result.F10. Robust and Worst-Case Optimization#
Pattern#
Optimize for worst-case performance under uncertainty.
Mathematical Structure#
- Variables: Decision variables
- Objective: Minimize worst-case cost or maximize worst-case performance
- Uncertainty: Set of possible scenarios (no probability distribution)
Problem Types#
- Robust LP: Reformulate as larger LP
- Robust convex: CVXPY with norm constraints
Generic Examples#
- Portfolio optimization: minimize worst-case loss
- Network design: maximize worst-case capacity
- Production planning: meet worst-case demand
- Control design: stability under worst-case disturbances
Use Case to Library Mapping#
| Use Case Pattern | Primary Library | Alternative | Problem Type |
|---|---|---|---|
| Resource Allocation | PuLP, Pyomo | scipy.optimize | LP, MILP, QP |
| Scheduling | OR-Tools CP-SAT | Pyomo | CP, MILP |
| Selection/Assignment | PuLP, OR-Tools | Pyomo | MILP |
| Network Flow | OR-Tools, Pyomo | PuLP | LP, MILP |
| Cutting/Packing | Pyomo, OR-Tools | PuLP | MILP |
| Blending | PuLP, Pyomo | scipy.optimize | LP |
| Portfolio | CVXPY | Pyomo | QP, Convex |
| Parameter Estimation | scipy.optimize | Pyomo+IPOPT | NLP |
| Multi-Objective | pymoo | CVXPY (weighted) | Multi-objective |
| Robust | CVXPY | Pyomo | Convex, LP |
Pattern Recognition Strategy#
When facing an optimization problem:
- Identify pattern: Does it match a known use case?
- Determine problem type: LP, MILP, NLP, convex, CP?
- Select library: Based on problem type and pattern
- Adapt generic model: Customize pattern to your specifics
- Validate: Test on small instance, verify results make sense
Most real problems are variations of these 10 patterns.
S4: Strategic
S4-Strategic: Academic vs Industrial Perspectives#
Academic Optimization#
Priorities#
- Correctness: Provably optimal solutions
- Generality: Handle wide problem classes
- Reproducibility: Open-source, documented algorithms
- Flexibility: Experiment with multiple solvers and formulations
- Cost: Free academic licenses, open-source preferred
Typical Use Cases#
- Operations research papers
- Algorithm development and comparison
- Teaching optimization courses
- Sensitivity analysis and theoretical studies
Tool Preferences#
Modeling languages: Pyomo (most flexible, 20+ solvers) Solvers: Mix of open-source (SCIP, IPOPT) and commercial (free academic licenses for Gurobi, CPLEX) Rationale: Need to compare approaches, document formulations
Academic Advantages#
- Free commercial solvers: Gurobi, CPLEX, MOSEK free for academic use
- Publication: Can test state-of-art solvers
- Time: Less time pressure, can wait for optimal solutions
Industrial Optimization#
Priorities#
- Time-to-solution: Fast enough for business needs
- Robustness: Handle real-world edge cases
- Maintainability: Code must be maintained by team
- Integration: Fit into existing systems
- Support: Professional support when things break
Typical Use Cases#
- Production scheduling
- Logistics and routing
- Resource allocation
- Real-time optimization services
Tool Preferences#
Production systems: OR-Tools (bundled, stable) or Pyomo + HiGHS/commercial Prototyping: PuLP, scipy.optimize (fast development) Commercial when: Performance critical, budget available
Industrial Constraints#
- Budget: $10k-100k/year for commercial solvers (must justify ROI)
- Time pressure: Solutions needed quickly, not necessarily optimal
- Team skills: Must be learnable by engineers who aren’t optimization PhDs
- Reliability: Downtime costs money
Key Differences#
| Aspect | Academic | Industrial |
|---|---|---|
| Optimality | Must be optimal | Good enough often fine |
| Solve time | Hours/days acceptable | Seconds/minutes required |
| Solver cost | Free (academic licenses) | Must justify ROI |
| Solver choice | Try many | Pick one, stick with it |
| Code quality | Research code acceptable | Production quality required |
| Documentation | Papers, LaTeX formulations | Code comments, docs |
| Validation | Mathematical proof | Business validation |
| Maintenance | Short-term (project duration) | Long-term (years) |
Open-Source vs Commercial Decision#
Academic Decision (Usually Easy)#
- Use free academic licenses for commercial solvers
- Also test open-source for reproducibility
- Report results from multiple solvers
Industrial Decision (Harder)#
- Start with open-source: HiGHS, SCIP, IPOPT
- Profile: Is solver the bottleneck?
- ROI analysis: Does faster solve time justify $10k-100k/year?
- Decision:
- If savings > cost → commercial
- If open-source sufficient → stay open-source
Reality: Many companies use open-source successfully (HiGHS, SCIP competitive for medium-scale problems)
Hybrid Approach (Common in Industry)#
Development: Open-source
- Develop with Pyomo + CBC/SCIP
- Zero licensing cost for development team
- Team can experiment freely
Production: Commercial (if justified)
- Deploy with Gurobi/CPLEX if performance critical
- Licensing cost justified by production value
- Pyomo makes this seamless (same model code)
Example:
# Development
solver = SolverFactory('cbc')
# Production (zero code change!)
solver = SolverFactory('gurobi')Tool Selection Patterns#
Academic Pattern#
- Learn Pyomo (most flexible)
- Get academic Gurobi/CPLEX licenses
- Also install open-source (SCIP, IPOPT) for reproducibility
- Use CVXPY for convex problems (DCP verification)
- Experiment with everything
Industrial Pattern#
- Start with simplest tool (PuLP, scipy.optimize)
- Validate business value with open-source
- Upgrade tools only when justified (complexity or performance)
- Minimize solver diversity (support cost)
- Production-ready libraries (OR-Tools, Pyomo + HiGHS)
Research to Production Translation#
Common Challenges#
Academic code → production code
- Research code often not production-quality
- Rewrite needed
Solver assumptions
- Academic: Gurobi available
- Industry: Must justify cost
Problem scale
- Academic: Toy instances
- Industry: Real-world size
Edge cases
- Academic: Well-formed problems
- Industry: Dirty data, infeasible scenarios
Best Practices#
Design for open-source first
- Develop with open-source solvers
- Upgrade to commercial only if needed
Use modeling languages
- Pyomo enables solver swapping
- Avoid direct API lock-in
Modular design
- Separate optimization from business logic
- Easy to swap optimization components
Test at scale
- Validate with real-world problem sizes
- Profile before optimizing
Case Studies#
Case 1: University Research → Startup#
Situation: Researchers start company based on optimization research
Approach:
- Prototype with academic Gurobi license
- Launch with Pyomo + SCIP (free, Apache 2.0)
- Offer “premium tier” with Gurobi for customers needing max performance
- Gradual adoption of commercial as revenue grows
Lesson: Open-source enables launch, commercial as upsell
Case 2: Enterprise Scheduling System#
Situation: Large company building scheduling system
Approach:
- Prototype with OR-Tools CP-SAT (free, production-ready)
- Performance excellent (award-winning CP solver)
- Never needed commercial
- Saved $100k+/year in licensing
Lesson: Open-source (OR-Tools) competitive for constraint programming
Case 3: Financial Portfolio Optimization#
Situation: Hedge fund, portfolio optimization
Approach:
- CVXPY for development (DCP verification catches errors)
- MOSEK solver (best for conic problems)
- $50k/year licensing justified by fund size
Lesson: Commercial justified when managing millions/billions
Future Trends#
Academia Driving#
- New algorithms (ML + optimization)
- Benchmark datasets (MIPLIB, etc.)
- Open-source solver development (SCIP, HiGHS)
Industry Driving#
- Production-ready tools (OR-Tools)
- Cloud optimization services
- Integration with ML pipelines
Convergence#
- Academic tools becoming production-ready
- Industry contributing to open-source
- HiGHS adoption (SciPy, MATLAB) bridges gap
Recommendations#
For Academics#
- Use Pyomo: Most flexible, academic standard
- Get free commercial licenses: Gurobi, CPLEX, MOSEK
- Also use open-source: SCIP, IPOPT for reproducibility
- CVXPY for convex: DCP verification invaluable
- Document formulations: Mathematical + code
For Industry#
- Start simple: PuLP, scipy.optimize, OR-Tools
- Validate value with open-source: Prove ROI before commercial
- Production-ready libraries: OR-Tools, Pyomo + HiGHS
- Commercial when justified: Large-scale, time-critical, ROI positive
- Plan for maintenance: Code quality, documentation, team skills
For Both#
- Problem type determines tool: Not domain
- Open-source competitive: Don’t assume commercial needed
- Pyomo for flexibility: Enables solver swapping
- Profile before optimizing: Measure, don’t guess
Key Insight#
The gap between academic and industrial optimization tools has narrowed dramatically. Open-source solvers (HiGHS, SCIP) and production-ready libraries (OR-Tools, Pyomo) enable industrial deployment without commercial solvers for many use cases. Commercial solvers still faster on largest instances, but threshold for “need commercial” has risen significantly.
Academic advantage (free commercial licenses) remains, but industrial users have excellent open-source options in 2025.
S4-Strategic: Ecosystem Maturity Analysis#
Python Optimization Ecosystem Overview#
The Python optimization ecosystem in 2025 is mature, diverse, and increasingly competitive with commercial alternatives.
Maturity Indicators#
Library Age and Stability#
| Library | First Release | Years Active | Maturity Assessment |
|---|---|---|---|
| scipy.optimize | ~2001 (scipy 0.x) | 20+ years | Very mature |
| PuLP | ~2003 | 20+ years | Mature |
| Pyomo | 2008 | 15+ years | Mature |
| OR-Tools | ~2010 | 15+ years | Mature |
| CVXPY | 2013 | 10+ years | Mature |
| GEKKO | 2018 | 6 years | Maturing |
| pymoo | 2019 | 5 years | Maturing |
Assessment: Core libraries (scipy, PuLP, Pyomo, OR-Tools) are mature and stable.
Development Activity (2024-2025)#
Very Active:
- OR-Tools: Python 3.13 support, muslinux wheels (2025)
- Pyomo: v6.9.4 (Sept 2025), new GDPopt algorithms
- pymoo: v0.6.1.5 (May 2025), Python 3.13 support
Active:
- scipy: Regular releases as part of scipy package
- CVXPY: Ongoing development
- PuLP: v3.3.0 (Sept 2025)
Assessment: All major libraries actively maintained.
Community Size#
| Library | GitHub Stars | Weekly Downloads | Community Size |
|---|---|---|---|
| scipy | Part of scipy/scipy | Millions (monthly) | Huge |
| OR-Tools | 12,600 | Part of ortools | Large |
| Pyomo | 2,127 | 123,641 | Medium-Large |
| CVXPY | Not checked | Thousands | Medium |
| PuLP | Part of COIN-OR | Thousands | Medium |
Assessment: Strong communities across major libraries.
Solver Ecosystem Maturity#
Open-Source Solver Development#
Major developments 2020-2025:
HiGHS emergence (2018-2021):
- Adopted by SciPy 1.6.0 (2021)
- Adopted by MATLAB Optimization Toolbox
- Signal of production readiness
SCIP Apache 2.0 (2024):
- SCIP 9.0 became fully open-source
- Removed academic-only licensing barrier
- Fastest academic MILP solver now freely usable
OR-Tools CP-SAT awards (2018-2021):
- MiniZinc Challenge medals
- Competitive with commercial CP solvers
Implication: Open-source solver quality approaching commercial.
Commercial Solver Landscape#
Stability: Gurobi, CPLEX, MOSEK remain dominant but…
Transparency reduction:
- Gurobi withdrew from Mittelmann benchmarks (Aug 2024)
- MindOpt followed (Dec 2024)
- Harder to compare commercial vs open-source performance
Pricing: $10k-100k+/year (enterprise), free (academic)
Assessment: Commercial still faster on largest instances but gap narrowing.
Integration Maturity#
Package Management#
- PyPI: All major libraries available
- conda: Most available via conda-forge
- Solver installation: Varying complexity
- Easy: OR-Tools, PuLP (bundled solvers)
- Moderate: Pyomo (install solvers separately)
- Complex: IPOPT (requires linear algebra libraries)
Python Version Support#
- All major libraries support Python 3.9+
- OR-Tools, pymoo support Python 3.13 (as of 2025)
- Assessment: Good Python version support
Cross-Platform#
- All libraries support Windows, Linux, MacOS
- OR-Tools provides platform-specific wheels
- Assessment: Excellent cross-platform support
Documentation Maturity#
| Library | Docs Quality | Tutorials | Examples | Textbook |
|---|---|---|---|---|
| scipy | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ❌ |
| Pyomo | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ✅ Springer |
| CVXPY | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ✅ Boyd & Vandenberghe |
| OR-Tools | ⭐⭐⭐⭐⭐ | ⭐⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ❌ |
| PuLP | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ | ❌ |
| GEKKO | ⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ | ❌ |
| pymoo | ⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐⭐ | ❌ |
Assessment: Documentation quality excellent for major libraries.
Academic Adoption#
Widely used in academia:
- Pyomo: Operations research standard
- CVXPY: Convex optimization (Stanford CVX101 course)
- OR-Tools: Google research
- scipy.optimize: Scientific computing
Publications:
- SciPy: Nature Methods 2020
- CVXPY: JMLR 2016
- pymoo: IEEE Access 2020
- Pyomo: Mathematical Programming Computation 2011
Assessment: Strong academic foundations and continued research use.
Industrial Adoption#
Known users:
- Google: OR-Tools (internal use)
- Tech companies: CVXPY for ML pipelines
- Finance: Portfolio optimization (CVXPY, commercial solvers)
- Logistics: Routing (OR-Tools, commercial)
Adoption signals:
- SciPy/MATLAB chose HiGHS (industry validation)
- OR-Tools production-ready (Google scale)
- Pyomo used in energy systems (DOE, national labs)
Assessment: Production-grade libraries available.
Gaps and Weaknesses#
- Solver installation complexity: Not as seamless as pure-Python packages
- Fragmentation: Many libraries, not always clear which to use
- Benchmark transparency: Commercial withdrawal from Mittelmann reduces comparability
- GUI/Modeling tools: Limited (mostly code-based, unlike GAMS/AMPL IDEs)
- Enterprise support: Open-source lacks professional support contracts
Strengths#
- Diversity: Libraries for every problem type
- Integration: Easy integration with data pipelines, ML, simulation
- Cost: Excellent open-source options
- Community: Active development and support
- Research: Strong academic backing
Maturity Trajectory#
Past (2000-2015):
- Commercial dominated
- Python optimization niche
Present (2016-2025):
- Open-source competitive
- Python becoming default for optimization
- HiGHS, SCIP close performance gap
Future (2025+):
- Continued open-source strengthening
- ML integration (learning to optimize)
- Cloud-native optimization services
Risk Assessment#
Low Risk (Mature, Stable)#
- scipy.optimize: Part of scipy (25+ years)
- PuLP: COIN-OR project (20+ years)
- Pyomo: Academic standard (15+ years)
- OR-Tools: Google-backed (15+ years)
Medium Risk (Maturing)#
- GEKKO: Smaller community, niche domain
- pymoo: Newer, but active development
Commercial Risk#
- Licensing costs: Budget variability
- Vendor lock-in: Switching costs
- API changes: Less community input
Recommendations#
- For new projects: Ecosystem is mature enough for production use
- Open-source first: Start with open-source, upgrade to commercial only if needed
- Community-backed libraries: Prefer scipy, Pyomo, CVXPY, OR-Tools (large communities)
- Commercial for scale: Very large problems may still need Gurobi/CPLEX
- Stay current: Ecosystem evolving rapidly (HiGHS, SCIP developments)
Conclusion#
Python optimization ecosystem in 2025 is mature and production-ready. Open-source quality has improved dramatically, with HiGHS, SCIP, and OR-Tools competitive with commercial alternatives for many use cases. Strong academic foundations, active development, and large communities make Python the default choice for optimization in data science and scientific computing.
Major libraries (scipy, Pyomo, CVXPY, OR-Tools, PuLP) are stable and suitable for production. The gap between open-source and commercial has narrowed significantly, especially for LP, medium-scale MILP, and constraint programming.
S4-Strategic: Future Trends in Optimization#
Emerging Trends (2025+)#
1. Machine Learning + Optimization Integration#
Learning to Optimize:
- ML models predict good branching variables (MILP)
- Learned heuristics replace hand-crafted rules
- Transfer learning across similar problem instances
Optimization for ML:
- Hyperparameter optimization (Optuna, specialized)
- Neural architecture search
- Adversarial training (min-max optimization)
Current status: Research → early production
- Gurobi exploring ML-enhanced branching
- Academic papers on learned optimizers
Python impact: Tight integration with PyTorch, TensorFlow, JAX for gradient-based optimization
2. Differentiable Optimization#
Concept: Embed optimization as differentiable layer in neural network
Enables:
- End-to-end learning with optimization in pipeline
- Backpropagate through optimization problem
- Learn constraint parameters
Libraries:
- cvxpylayers (CVXPY + PyTorch/TensorFlow)
- OptNet (differentiable QP layer)
- CasADi (automatic differentiation for NLP)
Applications:
- Robotics (learn + plan)
- Control (learn dynamics + optimize control)
- Structured prediction
Trend: Growing, especially in ML research
3. Cloud-Native Optimization#
Optimization-as-a-Service:
- Serverless optimization (AWS Lambda + optimization)
- Managed solvers (Azure Optimization, Google OR-Tools in cloud)
- Distributed MILP solving
Advantages:
- Elastic compute (solve large problems without local hardware)
- Pay-per-use (avoid solver licensing costs)
- Managed updates
Challenges:
- Data privacy (send problem to cloud)
- Latency (network overhead)
- Vendor lock-in
Current offerings:
- Amazon SageMaker (ML + optimization)
- Azure Optimization Service
- Google OR-Tools (can run on GCP)
Trend: Growing, especially for sporadic large solves
4. GPU-Accelerated Optimization#
Status: Early stage
Applications:
- Parallel LP solves (multiple RHS)
- Metaheuristics (population-based, embarrassingly parallel)
- Tree search in MILP (experimental)
Libraries:
- HiGHS: GPU support added (v1.10.0+)
- CUDA-based LP solvers (research)
Challenges:
- MILP inherently sequential (branch-and-bound)
- Memory bandwidth limitations
Trend: Experimental, not yet mainstream
5. Quantum Optimization#
Status: Research, 5-10+ years from practical
Approaches:
- Quantum annealing (D-Wave)
- Gate-based quantum algorithms (QAOA)
Current reality:
- Very limited problem sizes
- Specialized problems (QUBO)
- Classical often faster
Python libraries:
- Qiskit (IBM quantum)
- Ocean (D-Wave)
- PennyLane (quantum ML)
Trend: Long-term research, not production-ready
6. Automated Formulation#
Concept: AI suggests formulations given problem description
Research:
- Natural language → MILP formulation
- Automated reformulation for tighter relaxations
- Symmetry detection and breaking
Status: Very early research
Trend: Long-term (5+ years)
7. Explainable Optimization#
Motivation: Understand why solution is optimal
Techniques:
- Sensitivity analysis
- Constraint importance
- Alternative optimal solutions (Pareto frontier)
- Visualization
Python tools:
- Pyomo suffixes (dual values, reduced costs)
- CVXPY sensitivity analysis
- Custom visualization (matplotlib, plotly)
Trend: Growing, especially in high-stakes domains (healthcare, finance)
8. Robust and Stochastic Optimization#
Moving from:
- Deterministic optimization (assumes known parameters)
To:
- Robust (worst-case)
- Stochastic (probability distributions)
- Online (learn + adapt)
Python libraries:
- CVXPY (robust optimization with norm constraints)
- Pyomo.PySP → mpi-sppy (stochastic programming)
Applications:
- Supply chain under uncertainty
- Energy systems (renewable variability)
- Portfolio optimization (market uncertainty)
Trend: Growing as real-world uncertainty acknowledged
9. Real-Time and Online Optimization#
Context:
- Decisions needed in milliseconds (not hours)
- Parameters change dynamically
Approaches:
- Approximate solutions (feasible but suboptimal fast)
- Warm starting (use previous solution)
- Model Predictive Control (receding horizon)
Requirements:
- Fast solvers (HiGHS, commercial)
- Efficient re-optimization (persistent solvers)
Applications:
- Ride-sharing dispatch
- Real-time energy markets
- Robotics
Trend: Growing with real-time applications
10. Open-Source Solver Strengthening#
Observations:
- HiGHS adopted by SciPy, MATLAB
- SCIP now Apache 2.0 (removed barrier)
- OR-Tools award-winning
Prediction:
- Gap continues narrowing
- More production adoption of open-source
- Commercial edge on largest problems remains
Trend: Accelerating
Python-Specific Trends#
1. Consolidation Around Standards#
Likely: A few dominant libraries (Pyomo, CVXPY, OR-Tools, scipy) continue strengthening
2. Better Integration#
Likely: Tighter integration with data science stack (pandas, numpy, scikit-learn)
3. Type Hints and Tooling#
Emerging: Better IDE support, type checking for optimization code
4. JIT Compilation#
Possible: Numba, JAX compilation for faster model building
Implications for Users#
Short-Term (1-2 years)#
- Open-source sufficient for more use cases: Continue trying open-source first
- ML integration grows: Expect more optimization + ML hybrid approaches
- Cloud options expand: Consider cloud for large sporadic solves
Medium-Term (3-5 years)#
- Learned optimizers emerge: Solvers with ML-enhanced heuristics production-ready
- Differentiable optimization matures: Standard in robotics, control, ML pipelines
- Open-source competitive for most: Commercial edge only for largest problems
Long-Term (5-10 years)#
- Automated formulation: AI assists in problem formulation
- Quantum (maybe): Specialized applications only
- Real-time ubiquitous: Optimization everywhere (IoT, edge computing)
Strategic Recommendations#
For Organizations#
- Build on open-source: Future trends favor open-source strengthening
- Cloud-ready: Design for cloud deployment (data privacy permitting)
- Invest in ML + optimization: Emerging integration point
- Stay flexible: Use modeling languages (Pyomo) for solver swapping
For Researchers#
- ML + optimization: Hot area for research
- Differentiable optimization: Growing subfield
- Explainability: Underexplored area
- Contribute to open-source: Ecosystem strengthening
For Practitioners#
- Learn fundamentals: Problem types, formulations (won’t change)
- Master one library well: Pyomo (flexibility) or OR-Tools (production)
- Stay current: Ecosystem evolving rapidly
- Experiment with new tools: Try HiGHS, SCIP, new features
Wild Cards (Low Probability, High Impact)#
- Gurobi open-sources: Would transform landscape (unlikely)
- Quantum breakthrough: Earlier than expected practical quantum (very unlikely
<5years) - New algorithm class: Fundamental algorithmic breakthrough (possible but rare)
- Regulatory push: Government requires open-source for public sector (possible)
Conclusion#
Optimization in 2025+ will be:
- More integrated with ML pipelines
- More accessible (cloud, open-source)
- More real-time (fast solvers, approximate solutions)
- More automated (learned heuristics, automated formulation)
Python will remain dominant for optimization in data science and scientific computing. Open-source solvers will continue strengthening, making commercial solvers necessary only for the largest, most demanding problems.
The gap between research and production continues narrowing, with tools like HiGHS, SCIP, and OR-Tools demonstrating production-readiness of open-source optimization.
Key principle remains unchanged: Problem type determines tool selection. Future trends enhance tools, but fundamental optimization theory persists.
S4-Strategic: Solver Landscape 2025#
Open-Source Solver Status#
Linear Programming (LP)#
HiGHS (MIT License)
- Status: Rising star, production-ready
- Adoption: SciPy 1.6.0+, MATLAB default
- Performance: Competitive with commercial
- Algorithms: Dual simplex, primal simplex, interior point
- Assessment: Best open-source LP solver
CLP (Coin-OR, EPL)
- Status: Mature, stable
- Performance: Good, slower than HiGHS
- Part of: COIN-OR optimization suite
GLPK (GPL)
- Status: Widely available, basic performance
- Use case: Small problems, availability matters
- Limitation: GPL license (copyleft)
Mixed-Integer Linear Programming (MILP)#
SCIP (Apache 2.0 since v9.0)
- Status: Fastest academic MILP solver
- Major development: Now fully open-source (was academic-only)
- Performance: Competitive with commercial on many problems
- Also handles: MINLP
- Assessment: Best open-source MILP
CBC (COIN-OR, EPL)
- Status: Mature, widely used
- Bundled with: PuLP
- Performance: 2-5x slower than SCIP, adequate for small-medium
- Reliability: Very stable
HiGHS (MIT)
- Status: Also does MILP (not just LP)
- Performance: Good, improving
- Advantage: Same solver for LP and MILP
Nonlinear Programming (NLP)#
IPOPT (EPL)
- Status: Standard open-source NLP solver
- Algorithm: Interior point
- Scale: Large-scale capable
- Dependencies: Requires linear algebra library (HSL, MUMPS, Pardiso)
- Assessment: Industry standard for open-source NLP
- Limitation: Local optima (non-convex problems)
Bonmin, Couenne (EPL)
- Focus: MINLP (mixed-integer nonlinear)
- Status: Academic, slower
- Use case: When MINLP required and commercial not available
Convex Optimization#
Clarabel (Apache 2.0)
- Language: Rust
- Status: Modern, becoming CVXPY default
- Handles: SOCP, SDP, QP
SCS (MIT)
- Focus: Conic optimization
- Robustness: Very robust, medium accuracy
- Use case: Large-scale conic problems
OSQP (Apache 2.0)
- Focus: Quadratic programming (QP)
- Performance: Very fast for QP
- Use case: Model predictive control, embedded
ECOS (GPL)
- Focus: Second-order cone programming (SOCP)
- Performance: Fast for small-medium SOCP
Constraint Programming#
OR-Tools CP-SAT (Apache 2.0)
- Developer: Google
- Status: Award-winning (MiniZinc Challenge medals)
- Performance: Competitive with commercial CP solvers
- Assessment: Best-in-class open-source CP
Commercial Solver Status#
MILP Leaders#
Gurobi
- Pricing: ~$10k-100k+/year (enterprise), free (academic)
- Performance: Historically fastest MILP
- Benchmark status: Withdrew August 2024
- Support: Excellent professional support
- Adoption: Wide industry use
CPLEX (IBM)
- Pricing: Similar to Gurobi
- Performance: Competitive with Gurobi
- Strengths: High-dimensionality, non-convex MIQP
- Benchmark status: Still participates
- Enterprise: IBM support and integration
Xpress (FICO)
- Pricing: Similar tier
- Performance: Competitive
- Features: Mosel modeling language
NLP Specialists#
KNITRO (Artelys)
- Pricing: $5k-50k/year
- Performance: 2-10x faster than IPOPT on many problems
- Algorithms: Interior point, SQP, active set
- Use case: Large-scale nonlinear
SNOPT (Stanford)
- Focus: Sparse NLP
- Academic roots: Stanford research
- Adoption: Aerospace, engineering
Conic Optimization#
MOSEK
- Pricing: $5k-50k/year, free (academic)
- Focus: SOCP, SDP, conic optimization
- Performance: Significantly faster than open-source for conic
- Assessment: Best commercial conic solver
Global MINLP#
BARON
- Focus: Global MINLP solver
- Algorithm: Branch-and-reduce
- Performance: Slow (problem is hard), but finds global optima
- Use case: When global optimum required for non-convex
Solver Selection by Problem Type#
| Problem | Open-Source Leader | Commercial Leader | Gap |
|---|---|---|---|
| LP | HiGHS | Gurobi, CPLEX | Narrow |
| MILP (small-medium) | SCIP, HiGHS | Gurobi, CPLEX | Medium |
| MILP (large) | SCIP | Gurobi, CPLEX | Wide |
| NLP | IPOPT | Knitro, SNOPT | Medium |
| Convex conic | Clarabel, SCS | MOSEK | Wide |
| CP | OR-Tools CP-SAT | CPLEX CP | Narrow |
| Global MINLP | SCIP, Couenne | BARON | Medium |
Major Developments (2020-2025)#
- HiGHS adoption (2021): SciPy, MATLAB → production validation
- SCIP Apache 2.0 (2024): Removed licensing barrier
- Gurobi/MindOpt withdrawal (2024): Benchmark transparency reduced
- OR-Tools CP-SAT awards (2018-2021): Best-in-class CP
- Clarabel emergence (2023-2024): Modern Rust-based conic solver
Performance Trends#
Open-source improving:
- HiGHS: LP competitive with commercial
- SCIP: MILP gap narrowing
- CP-SAT: CP competitive/superior to commercial
Commercial maintaining edge:
- Very large MILP (100k+ variables, 10k+ integer)
- Conic optimization (MOSEK
>>open-source) - Professional support and features
Inflection point: Medium-scale problems (<10k integer variables) now often solvable with open-source.
Licensing Landscape#
Open-Source Licenses#
- MIT (HiGHS, SCS, OSQP): Most permissive
- Apache 2.0 (SCIP, OR-Tools, Clarabel): Permissive, patent protection
- EPL (IPOPT, CBC, CLP, Bonmin, Couenne): Weak copyleft
- GPL (GLPK, ECOS): Strong copyleft (limits commercial use)
Commercial Licenses#
- Named-user: Per-person
- Floating: Shared pool
- Cloud/Usage-based: Pay per solve
- Academic: Free but restricted to research/teaching
Future Outlook#
Likely Developments#
- Continued open-source strengthening: SCIP, HiGHS performance improvements
- ML integration: Learned heuristics in solvers
- Cloud-native: Optimization-as-a-service
- GPU acceleration: MILP on GPUs (early stage)
- Quantum: Long-term (10+ years)
Open Questions#
- Will commercial performance gap close completely? (Probably not, but threshold rising)
- Will Gurobi/CPLEX return to public benchmarks? (Unknown)
- Will more companies adopt open-source for production? (Likely yes)
Recommendations#
For Most Users#
Start with open-source:
- LP: HiGHS
- MILP: SCIP or HiGHS
- NLP: IPOPT
- Convex: CVXPY with Clarabel/SCS
- CP: OR-Tools CP-SAT
Upgrade to Commercial When#
- Very large MILP (
>100k variables,>10k integer) - Conic optimization (MOSEK)
- Professional support needed
- ROI justifies cost
Academic Users#
- Free commercial licenses available
- Test both open-source and commercial
- Report both for reproducibility
Key Insight#
Solver landscape in 2025 favors open-source for many use cases. HiGHS, SCIP, IPOPT, and OR-Tools are production-ready and competitive. Commercial solvers maintain edge on largest problems and provide professional support, but threshold for “need commercial” has risen significantly.
Strategic recommendation: Build on open-source, upgrade to commercial only when profiling demonstrates clear performance need. Pyomo enables seamless migration.