MIP Journey
Understand how integer programming solvers work
In This Path
- What is Mixed-Integer Programming? 20 min
- LP Relaxation and Bounds 30 min
- Branch-and-Bound Trees 45 min
- Cutting Planes 45 min
- Branching Strategies 30 min
- Primal Heuristics 30 min
- Putting It Together: Branch-and-Cut 40 min
This path builds on LP Fundamentals to show how MIP solvers handle integer variables. You'll understand why MIP is hard, how branch-and-bound explores solutions, and why cutting planes and heuristics make modern solvers practical.
Prerequisites
You should have completed LP Fundamentals or be comfortable with:
- The simplex method (primal and dual)
- LP duality and reduced costs
- Why LP can be solved efficiently
1. What is Mixed-Integer Programming?
MIP extends LP by requiring some variables to be integers:
$$\min_{x,y} \quad c^T x + d^T y$$ $$\text{s.t.} \quad Ax + By = b$$ $$\quad x \geq 0, \quad y \in \mathbb{Z}^p_{\geq 0}$$
Where $x$ are continuous and $y$ are integer variables.
Why Integers Matter
Many real decisions are discrete:
- Build a factory or not (binary: 0 or 1)
- Number of trucks to deploy (integer)
- Which routes to use (binary selection)
Why MIP is Hard
LP is solvable in polynomial time. MIP is NP-hard.
The Combinatorial Explosion
With $n$ binary variables, there are $2^n$ possible combinations:
- 20 variables → ~1 million combinations
- 40 variables → ~1 trillion combinations
- 100 variables → more than atoms in the universe
We can't enumerate. We need to be clever.
Types of Integer Programs
| Type | Variables | Example |
|---|---|---|
| Pure IP | All integer | Scheduling |
| Mixed IP (MIP) | Some integer, some continuous | Facility location |
| Binary IP | All 0-1 | Set covering |
| MIQCP | Integer + quadratic constraints | Portfolio with lots |
In COIN-OR, MIP is solved by Cbc (COIN-OR Branch and Cut). It uses Clp for LP relaxations and Cgl for cut generation.
2. LP Relaxation and Bounds
The key idea: relax integer constraints to get an LP, then use its solution to guide the search.
LP Relaxation
Drop the integrality requirements: $$y \in \mathbb{Z}^p \quad \rightarrow \quad y \in \mathbb{R}^p$$
The resulting LP is called the LP relaxation.
Why Relaxation Helps
Bounding property: For minimization: $$\text{LP optimal} \leq \text{MIP optimal}$$
The LP relaxation provides a lower bound on the best possible integer solution. This lets us prune parts of the search space.
Example
MIP: min $-x$ s.t. $x \leq 2.5$, $x \in \mathbb{Z}_{\geq 0}$
- LP relaxation optimal: $x = 2.5$, objective = $-2.5$
- MIP optimal: $x = 2$, objective = $-2$
The LP bound ($-2.5$) is valid but optimistic.
The Integrality Gap
$$\text{Gap} = \frac{\text{MIP optimal} - \text{LP optimal}}{\text{MIP optimal}}$$
Smaller gaps mean:
- LP relaxation is a good approximation
- Branch-and-bound will be faster
- Cutting planes are more effective
Cbc tracks bounds in CbcModel. The method getBestPossibleObjValue() returns the current lower bound from the LP relaxation.
3. Branch-and-Bound Trees
Branch-and-bound systematically explores the solution space by dividing it into smaller subproblems.
The Algorithm
Step 1: Solve LP Relaxation
At each node, solve the LP. If solution is integer-feasible, we have a candidate.
Step 2: Check Pruning Conditions
Prune (don't explore further) if:
- LP is infeasible (no integer solution possible)
- LP bound ≥ best known integer solution (can't improve)
- Solution is integer-feasible (record if best)
Step 3: Branch
Choose a fractional variable $y_j = f$ (e.g., $f = 2.7$).
Create two children:
- Left branch: Add $y_j \leq \lfloor f \rfloor$ (i.e., $y_j \leq 2$)
- Right branch: Add $y_j \geq \lceil f \rceil$ (i.e., $y_j \geq 3$)
Step 4: Select Next Node
Choose which unexplored node to process next (see node selection strategies below).
Visualizing the Tree
Root (LP: -2.5)
/ \
y₁ ≤ 2 y₁ ≥ 3
| |
Node 1 (LP: -2.3) Node 2 (LP: -2.8)
Integer! Best = -2.3 Better bound, explore...
/ \
y₂ ≤ 1 y₂ ≥ 2
| |
Infeasible Pruned (bound ≥ -2.3)
Node Selection Strategies
| Strategy | Description | When to use |
|---|---|---|
| Best-first | Explore node with best bound | Prove optimality |
| Depth-first | Explore deepest node | Find solutions fast, low memory |
| Best-estimate | Use heuristic prediction | Balance exploration |
| Diving | Go deep, then backtrack | Find good solutions early |
The power of pruning: If we find a good solution early (incumbent), we can prune huge parts of the tree. This is why primal heuristics matter so much.
CbcModel manages the tree. CbcNode represents nodes. Tree traversal strategies are in CbcTree and CbcCompare* classes. See branch-and-bound tree search.
4. Cutting Planes
Cutting planes tighten the LP relaxation by adding constraints that cut off fractional solutions without removing integer solutions.
What is a Cutting Plane?
A valid inequality $\alpha^T x \leq \beta$ that:
- Is satisfied by all integer-feasible points
- Cuts off the current fractional LP solution
Example: Gomory Cut
If the LP solution has $y_1 = 2.7$ with tableau row: $$y_1 + 0.3y_2 - 0.5y_3 = 2.7$$
The Gomory cut captures that the fractional parts must sum to an integer: $$0.3y_2 + 0.5y_3 \geq 0.7$$
(Because $y_1$ must be integer, the fractional contributions from $y_2, y_3$ must compensate.)
Types of Cuts
| Cut Type | What it exploits | Generated by |
|---|---|---|
| Gomory | Simplex tableau structure | CglGomory |
| Knapsack cover | Knapsack constraints | CglKnapsackCover |
| Clique | Conflicts between binaries | CglClique |
| MIR (Mixed Integer Rounding) | Mixing integer and continuous | CglMixedIntegerRounding |
| Flow cover | Network structure | CglFlowCover |
| Lift-and-project | Disjunctions | CglLandP |
Why cuts help: Each cut tightens the LP relaxation, bringing the LP optimum closer to the MIP optimum. This reduces the integrality gap, which means:
- Better bounds at each node
- More nodes can be pruned
- Faster convergence to optimality
Cut Management
Adding too many cuts can slow down the LP. Solvers manage cuts by:
- Limiting cuts per round
- Removing inactive cuts
- Aging out old cuts
The Cgl library provides cut generators. CbcModel calls them via CglCutGenerator. See the lift-and-project algorithm.
5. Branching Strategies
How you choose which variable to branch on dramatically affects performance.
Most Fractional
Branch on the variable closest to 0.5 (most "undecided").
Pros: Simple, no overhead Cons: Often inefficient
Pseudo-cost Branching
Track history: for each variable, record how much the LP bound changed when branching on it before.
$$\text{score}_j = f_j \cdot \text{down_pseudo} + (1-f_j) \cdot \text{up_pseudo}$$
Pros: Learns from experience Cons: No history at start
Strong Branching
Actually solve the LP for both branches (partially) to estimate bound improvement.
Pros: Best predictions Cons: Expensive (many LPs per node)
Reliability Branching
Hybrid: use strong branching until pseudo-costs are "reliable" (enough observations), then switch.
The trade-off: Better branching decisions mean fewer nodes, but each decision takes time. Modern solvers use adaptive strategies that invest more in branching decisions near the root (where impact is highest).
Cbc's branching strategies are in CbcBranch* classes. CbcBranchDynamic implements reliability branching. See branching variable selection.
6. Primal Heuristics
Heuristics find good (not necessarily optimal) integer solutions fast. A good incumbent enables massive pruning.
Why Heuristics Matter
Without an incumbent, we can't prune anything. The sooner we find a good solution:
- The more we can prune
- The better our gap estimate
- The faster we converge
Common Heuristics
Rounding
Round the LP solution to integers. Simple but often infeasible.
Variants: round toward integer, round to improve feasibility.
Feasibility Pump
Iterate between:
- Round LP solution to nearest integers
- Solve LP to get closest point to rounded solution
Converges to an integer-feasible point.
RINS (Relaxation Induced Neighborhood Search)
Fix variables that agree between LP and current incumbent. Solve the reduced MIP.
Uses the incumbent to guide the search.
Diving
Greedily round variables one at a time, re-solving LP after each. If infeasible, backtrack.
Heuristic scheduling: Solvers run different heuristics at different times:
- Root node: extensive search (feasibility pump, RINS)
- During tree: lightweight heuristics (rounding)
- Periodically: local search to improve incumbent
Cbc heuristics inherit from CbcHeuristic. See CbcHeuristicFPump for feasibility pump and CbcHeuristicRINS for RINS. The primal heuristics framework documents the design.
7. Putting It Together: Branch-and-Cut
Modern MIP solvers combine everything into branch-and-cut:
The Full Algorithm
Presolve
Simplify the problem: fix variables, tighten bounds, detect infeasibility.
Root Node Processing
- Solve LP relaxation
- Generate cutting planes (multiple rounds)
- Run primal heuristics extensively
- Establish initial incumbent and bound
Branch-and-Bound Tree Search
While unexplored nodes remain and gap > tolerance:
- Select a node
- Solve LP (warm-starting from parent)
- Try to prune
- If fractional: generate cuts, run heuristics, branch
Postsolve
Map solution back to original problem space.
Performance in Practice
| Technique | Typical impact |
|---|---|
| Presolve | 2-10x speedup |
| Root cuts | 10-100x speedup |
| Good incumbent | 10-1000x speedup |
| Strong branching | 2-5x speedup |
Why modern solvers are fast: It's not any single technique—it's the combination. Good cuts reduce the tree size. Good heuristics enable pruning. Good branching minimizes nodes visited. All together, they can solve problems that would be impossible with basic branch-and-bound.
Monitoring Progress
Solvers report:
- Gap:
(incumbent - bound) / incumbent— how far from optimal - Nodes: Number explored and remaining
- Time: Wall clock and per-node
When gap reaches tolerance (often 0.01%), solver declares optimal.
The main loop is in CbcModel::branchAndBound(). See branch-and-cut algorithm.
What's Next?
You now understand the core MIP algorithms! Next steps:
- Browse Cbc source - See the implementation
- Cutting plane algorithms - Deep dive on specific cuts
- Try it: Solve a MIP with Cbc and watch the log output. Match what you see to the concepts here.
You've learned:
- Why MIP is computationally hard (combinatorial explosion)
- How LP relaxation provides bounds
- Branch-and-bound tree search
- Cutting planes and why they help
- Branching strategies and their trade-offs
- Primal heuristics for finding incumbents
- How branch-and-cut puts it all together
You can now read Cbc code and understand what it's doing!