Choosing a Solver

This guide helps you choose the right solver for your optimization problem.

Quick Decision Tree

        graph TD
    A[Start] --> B{Need Continuous Variables?}
    B -->|No| C{Budget/License?}
    B -->|Yes| D{Need Quadratic/SOCP?}

    C -->|Free| E[CP-SAT<br/>Best for Scheduling]
    C -->|Commercial OK| F{Academic?}

    D -->|Yes| G{License Available?}
    D -->|No| H{Problem Size?}

    F -->|Yes| I[Gurobi or CPLEX<br/>Free Academic License]
    F -->|No| I

    G -->|Yes| I
    G -->|No| J[Use Linearization<br/>+ OR-Tools]

    H -->|Small/Medium| K[OR-Tools<br/>Free, Good Performance]
    H -->|Large| L[Gurobi/CPLEX<br/>Best Performance]
    H -->|Very Small| M[GLPK<br/>Basic, Free]

    style E fill:#90EE90
    style I fill:#FFD700
    style J fill:#87CEEB
    style K fill:#90EE90
    style L fill:#FFD700
    style M fill:#DDA0DD
    

Decision Factors

1. Problem Type

Linear Programming (LP)

Only continuous variables, linear constraints:

# Example: Portfolio optimization
max: profit_A * x_A + profit_B * x_B
s.t.: x_A + x_B <= budget
      x_A, x_B >= 0  (continuous)

Recommendation:

  • Best: Gurobi, CPLEX

  • Good: OR-Tools

  • Basic: GLPK

Mixed-Integer Programming (MIP)

Mix of continuous and integer/binary variables:

# Example: Facility location
max: revenue - fixed_cost * is_open
s.t.: is_open in {0, 1}  (binary)
      production >= 0     (continuous)

Recommendation:

  • Best: Gurobi, CPLEX

  • Good: OR-Tools

  • Basic: GLPK (small problems), CP-SAT (integer only)

Quadratic Programming (QP)

Quadratic objective or constraints:

# Example: Variance minimization
min: x^T * Covariance * x
s.t.: sum(x) = 1

Recommendation:

  • Best: Gurobi, CPLEX

  • Alternative: OR-Tools with linearization

Scheduling/Assignment

Pure integer assignment problems:

# Example: Employee scheduling
assign[worker, shift] in {0, 1}
s.t.: sum(assign[w, s] for s in shifts) <= 5  # Max 5 shifts per worker

Recommendation:

  • Best: CP-SAT (designed for this)

  • Alternative: Gurobi, CPLEX, OR-Tools

2. Budget and Licensing

Free and Open-Source

OR-Tools

  • License: Apache 2.0 (permissive)

  • Cost: Free

  • Best for: Most LP/MIP problems

  • Performance: Good

GLPK

  • License: GPL v3 (copyleft)

  • Cost: Free

  • Best for: Small problems, teaching

  • Performance: Moderate

  • Warning: GPL license has viral copyleft provisions

CP-SAT

  • License: Apache 2.0 (permissive)

  • Cost: Free

  • Best for: Integer programming, scheduling

  • Performance: Excellent (for its domain)

Commercial with Academic Licenses

Gurobi

  • License: Commercial (free academic)

  • Cost: Free for academic use, commercial pricing for businesses

  • Best for: Large-scale, production, research

  • Performance: Excellent

  • Get academic license: https://www.gurobi.com/academia/

CPLEX

  • License: Commercial (free academic via IBM Academic Initiative)

  • Cost: Free for academic use, commercial pricing for businesses

  • Best for: Enterprise, academic research

  • Performance: Excellent

  • Get academic license: IBM Academic Initiative

3. Problem Size

Small Problems (<1000 variables, <1000 constraints)

All solvers work well:

  • OR-Tools: Good default

  • GLPK: Acceptable for simple problems

  • CP-SAT: Excellent for integer problems

  • Gurobi/CPLEX: Overkill but work perfectly

Medium Problems (1K-100K variables/constraints)

  • Best: Gurobi, CPLEX

  • Good: OR-Tools

  • Avoid: GLPK (too slow)

Large Problems (>100K variables/constraints)

  • Best: Gurobi, CPLEX (commercial features, parallel solving)

  • Acceptable: OR-Tools (may be slower)

  • Avoid: GLPK, CP-SAT

4. Required Features

Quadratic Programming

  • Native support: Gurobi, CPLEX only

  • Via linearization: OR-Tools, GLPK (with LumiX linearization)

Second-Order Cone Programming (SOCP)

  • Supported: Gurobi, CPLEX

  • Not supported: OR-Tools, GLPK, CP-SAT

Piecewise-Linear Functions

  • Native: Gurobi, CPLEX

  • Via linearization: OR-Tools, GLPK (with LumiX)

SOS Constraints (SOS1, SOS2)

  • Supported: Gurobi, CPLEX, OR-Tools

  • Not supported: GLPK, CP-SAT

Indicator Constraints

  • Supported: Gurobi, CPLEX, OR-Tools

  • Not supported: GLPK

Sensitivity Analysis

  • Supported: Gurobi, CPLEX, GLPK

  • Not supported: OR-Tools, CP-SAT

Callbacks (Lazy Constraints, Cuts)

  • Supported: Gurobi, CPLEX

  • Not supported: OR-Tools, GLPK, CP-SAT

Warm Start

  • Supported: Gurobi, CPLEX, OR-Tools, CP-SAT

  • Not supported: GLPK

5. Performance Requirements

Interactive/Real-Time (sub-second response)

  • Gurobi, CPLEX (best)

  • OR-Tools (good for smaller problems)

  • CP-SAT (excellent for scheduling)

Batch Processing (minutes acceptable)

  • Any solver works

  • Consider OR-Tools to save licensing costs

Production Systems (reliability critical)

  • Gurobi, CPLEX (proven, supported)

  • OR-Tools (good, but less enterprise support)

Solver Comparison

Feature Matrix

Feature

OR-Tools

Gurobi

CPLEX

GLPK

CP-SAT

Linear (LP)

Integer (MIP)

✓ (only)

Quadratic

SOCP

SOS1/SOS2

Indicator

PWL

Sensitivity

Callbacks

Warm Start

Parallel

License

Free

Commercial

Commercial

Free (GPL)

Free

Performance Comparison

Relative performance (problem-dependent):

Problem Type

OR-Tools

Gurobi

CPLEX

GLPK

CP-SAT

Small LP

9/10

10/10

10/10

7/10

N/A

Large LP

7/10

10/10

10/10

3/10

N/A

Small MIP

8/10

10/10

10/10

6/10

9/10

Large MIP

7/10

10/10

10/10

2/10

7/10

Quadratic

N/A

10/10

10/10

N/A

N/A

Scheduling

7/10

10/10

10/10

3/10

10/10

Practical Recommendations

By Use Case

Academic Research

# Get free Gurobi academic license
optimizer = LXOptimizer().use_solver("gurobi")

Why?

  • Free for academic use

  • Best performance

  • Full features (sensitivity, callbacks)

  • Industry-standard for publications

Startup/Small Business

# Start with OR-Tools
optimizer = LXOptimizer().use_solver("ortools")

Why?

  • No licensing costs

  • Good performance for most problems

  • Can upgrade to Gurobi/CPLEX later if needed

Enterprise

# Use Gurobi or CPLEX
optimizer = LXOptimizer().use_solver("gurobi")

Why?

  • Best performance

  • Professional support

  • Proven reliability

  • Worth the cost for business-critical applications

Open-Source Project

# Use OR-Tools (Apache 2.0 license)
optimizer = LXOptimizer().use_solver("ortools")

Why?

  • Permissive license (no copyleft)

  • No commercial restrictions

  • Avoid GLPK’s GPL restrictions

Teaching/Learning

# OR-Tools or GLPK
optimizer = LXOptimizer().use_solver("ortools")

Why?

  • Free

  • Easy to install

  • Good for learning concepts

Scheduling/Rostering

# Use CP-SAT
optimizer = LXOptimizer().use_solver("cpsat")

Why?

  • Designed for scheduling problems

  • Excellent performance

  • Free

  • Handles complex logical constraints

Migration Strategy

Start Small, Scale Up

# Phase 1: Prototype with OR-Tools (free)
optimizer = LXOptimizer().use_solver("ortools")
solution = optimizer.solve(prototype_model)

# Phase 2: Test with Gurobi academic license
optimizer = LXOptimizer().use_solver("gurobi")
solution = optimizer.solve(full_model)

# Phase 3: Production with commercial Gurobi
optimizer = LXOptimizer().use_solver("gurobi")
solution = optimizer.solve(production_model, Threads=32)

Graceful Degradation

def get_best_available_solver():
    """Try solvers in order of preference."""
    try:
        return LXOptimizer().use_solver("gurobi")
    except ImportError:
        try:
            return LXOptimizer().use_solver("cplex")
        except ImportError:
            # Fall back to free solver
            return LXOptimizer().use_solver("ortools")

optimizer = get_best_available_solver()

Benchmarking

Always benchmark with your specific problem:

import time

solvers = ["ortools", "gurobi", "cplex"]
results = {}

for solver_name in solvers:
    try:
        optimizer = LXOptimizer().use_solver(solver_name)
        start = time.time()
        solution = optimizer.solve(model, time_limit=300)
        elapsed = time.time() - start

        results[solver_name] = {
            "time": elapsed,
            "objective": solution.objective_value,
            "status": solution.status
        }
    except ImportError:
        print(f"{solver_name} not available")

# Compare results
for solver, result in results.items():
    print(f"{solver}: {result['time']:.2f}s, obj={result['objective']:.2f}")

Common Scenarios

Scenario 1: Student Project

Requirements:

  • Free

  • Learn optimization

  • Small problems

Recommendation: OR-Tools

optimizer = LXOptimizer().use_solver("ortools")

Scenario 2: PhD Research

Requirements:

  • Academic use

  • Need best performance

  • Publish results

Recommendation: Gurobi (free academic license)

optimizer = LXOptimizer().use_solver("gurobi")

Scenario 3: SaaS Product

Requirements:

  • Cost-sensitive

  • Medium-scale problems

  • Need reliability

Recommendation: OR-Tools initially, evaluate Gurobi if performance becomes issue

# Start with OR-Tools
optimizer = LXOptimizer().use_solver("ortools")

# Upgrade path if needed:
# optimizer = LXOptimizer().use_solver("gurobi")

Scenario 4: Enterprise Optimization

Requirements:

  • Large-scale

  • Production-critical

  • Need support

Recommendation: Gurobi or CPLEX

optimizer = LXOptimizer().use_solver("gurobi")
solution = optimizer.solve(model, Threads=64, time_limit=3600)

Scenario 5: Employee Scheduling

Requirements:

  • Complex logical constraints

  • Integer variables only

  • Free solution preferred

Recommendation: CP-SAT

optimizer = (
    LXOptimizer()
    .use_solver("cpsat")
    .enable_rational_conversion()  # For any float coefficients
)

Next Steps