- name
- ortools
- description
- Google Optimization Tools. An open-source software suite for optimization, specialized in vehicle routing, flows, integer and linear programming, and constraint programming. Features the world-class CP-SAT solver. Use for vehicle routing problems (VRP), scheduling, bin packing, knapsack problems, linear programming (LP), integer programming (MIP), network flows, constraint programming, combinatorial optimization, resource allocation, shift scheduling, job-shop scheduling, and discrete optimization problems.
- version
- 9.8
- license
- Apache-2.0
# Google OR-Tools - Combinatorial Optimization
OR-Tools provides specialized solvers for hard combinatorial problems. Its crown jewel is the CP-SAT solver, which uses Constraint Programming and Satisfiability techniques to find optimal solutions for scheduling and resource allocation problems that are impossible for standard linear solvers.
## When to Use
- **Vehicle Routing (VRP)**: Finding the best paths for a fleet of vehicles to deliver goods.
- **Scheduling**: Creating shift rosters, project timelines, or job-shop schedules.
- **Bin Packing**: Fitting objects of different sizes into a finite number of bins.
- **Knapsack Problem**: Selecting items to maximize value within a weight limit.
- **Linear Programming (LP)**: Standard resource allocation with continuous variables.
- **Integer Programming (MIP)**: Optimization where variables must be whole numbers (e.g., "number of machines to buy").
- **Network Flows**: Calculating max flow or min cost in a graph.
## Reference Documentation
**Official docs**: https://developers.google.com/optimization
**GitHub**: https://github.com/google/or-tools
**Search patterns**: `cp_model.CpModel`, `pywraplp.Solver`, `routing_enums_pb2`, `AddConstraint`
## Core Principles
### Modeling vs. Solving
OR-Tools separates the **Definition** of the problem (Variables, Constraints, Objective) from the **Solver** engine. You build a model, then pass it to a solver instance.
### CP-SAT (Constraint Programming)
The most modern and recommended solver for discrete problems. **Critical Note**: CP-SAT works with integers only. If you have floating-point numbers (like `0.5`), you must scale them (e.g., multiply by 100 and work with integers).
### Status Codes
After solving, always check the status. It can be `OPTIMAL`, `FEASIBLE` (a solution found, but maybe not the best), `INFEASIBLE` (impossible to solve), or `LIMIT_REACHED`.
## Quick Reference
### Installation
```bash
pip install ortools
```
### Standard Imports
```python
from ortools.sat.python import cp_model
from ortools.linear_solver import pywraplp
from ortools.constraint_solver import routing_enums_pb2
from ortools.constraint_solver import pywrapcp
```
### Basic Pattern - CP-SAT Solver (Integer Logic)
```python
from ortools.sat.python import cp_model
# 1. Create the model
model = cp_model.CpModel()
# 2. Define variables: NewIntVar(lower_bound, upper_bound, name)
x = model.NewIntVar(0, 10, 'x')
y = model.NewIntVar(0, 10, 'y')
# 3. Add constraints
model.Add(x + y <= 8)
model.Add(x > 2)
# 4. Define Objective
model.Maximize(x + 2 * y)
# 5. Solve
solver = cp_model.CpSolver()
status = solver.Solve(model)
if status == cp_model.OPTIMAL:
print(f'x = {solver.Value(x)}, y = {solver.Value(y)}')
```
## Critical Rules
### ✅ DO
- **Use CP-SAT for Discrete Tasks** - It is significantly faster than MIP solvers for scheduling and logic-heavy problems.
- **Scale your Floats** - Since CP-SAT is an integer solver, convert `1.25` to `125` and adjust the logic.
- **Check Status First** - Never access variable values if the status is `INFEASIBLE`.
- **Use AddElement for indexing** - To use a variable as an index in an array, use the specialized constraint `model.AddElement`.
- **Set a Time Limit** - For complex problems, use `solver.parameters.max_time_in_seconds = 60.0` to get the best possible solution within a minute.
- **Verify with Value()** - Access results using `solver.Value(var)`, not the variable object itself.
### ❌ DON'T
- **Don't use Python if in Constraints** - You cannot use `if x > 5: model.Add(...)`. Use boolean implications (`OnlyEnforceIf`).
- **Don't use non-linear math** - CP-SAT and LP solvers don't support `x * y` (where both are variables) or `sin(x)`. For `x * y`, you need specialized linearization or piecewise approximations.
- **Avoid huge domains** - Defining a variable with a range of 0 to 1,000,000,000 can slow down the solver. Narrow the bounds as much as possible.
## Anti-Patterns (NEVER)
```python
from ortools.sat.python import cp_model
# ❌ BAD: Using standard Python logic inside the model
# if solver.Value(x) > 5: # ❌ Value() is not available during modeling!
# model.Add(y == 1)
# ✅ GOOD: Conditional constraints (Logical Implication)
b = model.NewBoolVar('b')
model.Add(x > 5).OnlyEnforceIf(b)
model.Add(x <= 5).OnlyEnforceIf(b.Not())
model.Add(y == 1).OnlyEnforceIf(b)
# ❌ BAD: Floating point variables in CP-SAT
# x = model.NewIntVar(0, 1.5, 'x') # ❌ Error!
# ✅ GOOD: Scaling
# x_scaled = model.NewIntVar(0, 150, 'x_scaled') # 150 represents 1.50
```
## Linear Programming (pywraplp)
### Resource Allocation (Continuous Variables)
```python
from ortools.linear_solver import pywraplp
# Create solver with GLOP backend (Google Linear Optimization Package)
solver = pywraplp.Solver.CreateSolver('GLOP')
# Define continuous variables
x = solver.NumVar(0, solver.infinity(), 'x')
y = solver.NumVar(0, solver.infinity(), 'y')
# Constraint: x + 2y <= 14
ct = solver.Constraint(-solver.infinity(), 14)
ct.SetCoefficient(x, 1)
ct.SetCoefficient(y, 2)
# Objective: Maximize 3x + 4y
objective = solver.Objective()
objective.SetCoefficient(x, 3)
objective.SetCoefficient(y, 4)
objective.SetMaximization()
solver.Solve()
print(f'Solution: x={x.solution_value()}, y={y.solution_value()}')
```
## Vehicle Routing (VRP)
### The Logistics Engine
```python
from ortools.constraint_solver import routing_enums_pb2
from ortools.constraint_solver import pywrapcp
def solve_vrp():
# 1. Distance Matrix (distance between locations)
data = {'distance_matrix': [[0, 10, 20], [10, 0, 15], [20, 15, 0]],
'num_vehicles': 1, 'depot': 0}
# 2. Setup Index Manager and Routing Model
manager = pywrapcp.RoutingIndexManager(len(data['distance_matrix']),
data['num_vehicles'], data['depot'])
routing = pywrapcp.RoutingModel(manager)
# 3. Create Distance Callback
def distance_callback(from_index, to_index):
return data['distance_matrix'][manager.IndexToNode(from_index)][manager.IndexToNode(to_index)]
transit_callback_index = routing.RegisterTransitCallback(distance_callback)
routing.SetArcCostEvaluatorOfAllVehicles(transit_callback_index)
# 4. Solve
search_parameters = pywrapcp.DefaultRoutingSearchParameters()
search_parameters.first_solution_strategy = (
routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC)
solution = routing.SolveWithParameters(search_parameters)
return solution
```
## Constraint Programming: Scheduling
### Job-Shop Example (Tasks with dependencies)
```python
model = cp_model.CpModel()
# Define an Interval Variable (Start, Duration, End)
duration = 10
start_var = model.NewIntVar(0, 100, 'start')
end_var = model.NewIntVar(0, 100, 'end')
interval_var = model.NewIntervalVar(start_var, duration, end_var, 'interval')
# No-overlap constraint (Machines can only do one task at a time)
model.AddNoOverlap([interval_var1, interval_var2, interval_var3])
```
## Practical Workflows
### 1. Employee Shift Scheduling
```python
def solve_shifts(num_employees, num_days, shifts_per_day):
model = cp_model.CpModel()
shifts = {}
for e in range(num_employees):
for d in range(num_days):
for s in range(shifts_per_day):
shifts[(e, d, s)] = model.NewBoolVar(f'shift_e{e}d{d}s{s}')
# Constraint: Each shift is assigned to exactly one employee
for d in range(num_days):
for s in range(shifts_per_day):
model.Add(sum(shifts[(e, d, s)] for e in range(num_employees)) == 1)
# Constraint: Each employee works at most one shift per day
for e in range(num_employees):
for d in range(num_days):
model.Add(sum(shifts[(e, d, s)] for s in range(shifts_per_day)) <= 1)
solver = cp_model.CpSolver()
status = solver.Solve(model)
return shifts, solver
```
### 2. Multi-Knapsack (Packing items into bins)
```python
def bin_packing(items, bin_capacities):
model = cp_model.CpModel()
# x[i, j] = 1 if item i is in bin j
x = {}
for i in range(len(items)):
for j in range(len(bin_capacities)):
x[i, j] = model.NewBoolVar(f'x_{i}_{j}')
# Each item in exactly one bin
for i in range(len(items)):
model.Add(sum(x[i, j] for j in range(len(bin_capacities))) == 1)
# Bin capacity constraint
for j in range(len(bin_capacities)):
model.Add(sum(x[i, j] * items[i] for i in range(len(items))) <= bin_capacities[j])
```
## Performance Optimization
### Hinting (Warm Start)
If you have a good initial guess, provide it to the solver to speed up search.
```python
model.AddHint(x, 5)
model.AddHint(y, 2)
```
### Parallel Solving
CP-SAT can use multiple threads to explore different parts of the search tree.
```python
solver = cp_model.CpSolver()
solver.parameters.num_search_workers = 8 # Use 8 CPU cores
```
## Common Pitfalls and Solutions
### Floating Point Math Errors
As mentioned, OR-Tools CP-SAT is strictly integer.
```python
# ❌ Problem: model.Add(x * 0.1 <= 5)
# ✅ Solution:
model.Add(x <= 50) # Multiply both sides by 10
```
### Infeasible Models
If `solver.Solve(model)` returns `INFEASIBLE`, it means your constraints are contradictory.
```python
# ✅ Solution: Use 'Sufficient Assmptions' or 'Constraint Relaxation'
# to identify which constraint is causing the conflict.
```
### Symmetry
If items A and B are identical, the solver will waste time checking both "A in Bin 1, B in Bin 2" and "B in Bin 1, A in Bin 2".
```python
# ✅ Solution: Add symmetry-breaking constraints
# model.Add(x_A <= x_B) # Force an ordering
```
## Best Practices
1. **Always check solver status** before accessing variable values
2. **Scale floating-point values** to integers when using CP-SAT
3. **Set time limits** for complex problems to get feasible solutions quickly
4. **Use appropriate solver** - CP-SAT for discrete, GLOP for continuous LP
5. **Break symmetry** in models with identical variables to speed up solving
6. **Narrow variable domains** as much as possible for better performance
7. **Use hints** when you have good initial guesses
8. **Enable parallel solving** for large problems when available
9. **Verify solutions** by checking constraints are satisfied
10. **Document your model** - variable names and constraint logic
Google OR-Tools is the heavy machinery of the optimization world. It solves the discrete puzzles that power global logistics, airline scheduling, and manufacturing, turning impossible "Trial and Error" into mathematical certainty.
GitHubで見る