Google OR-Tools Deep Dive: Constraint Solving and Decision Optimization in coomia-dip
1. [OR-Tools in coomia-dip](#1-or-tools-in-coomia-dip)
CoomiaPublished on November 27, 20257 min read
Share this articleTwitter / X
“Series: S8 Technology Deep Dives · Article 18 | Level: Advanced | Reading Time: 20 min
Google OR-Tools Deep Dive: Constraint Solving and Decision Optimization in coomia-dip
#TL;DR
- Google OR-Tools is the core optimization engine for coomia-dip's Reasoning & Decision Layer (Reasoning & Decision Layer), providing mathematical optimization for resource allocation, route planning, and scheduling
- This article analyzes OR-Tools' four solvers (LP/MIP/CP-SAT/Routing), modeling methodology, and 5 typical optimization scenarios in coomia-dip
- Covers objective function design, constraint modeling, solver parameter tuning, solution quality evaluation, and Ontology data model integration
#Table of Contents
- OR-Tools in coomia-dip
- Four Solvers
- Linear and Mixed-Integer Programming
- CP-SAT Constraint Programming
- Route Optimization
- Job Scheduling
- Resource Allocation
- Ontology Integration
- Solver Performance Tuning
- Production Deployment
- Key Takeaways
#1. OR-Tools in coomia-dip
#1.1 Decision Optimization Scenarios
| Scenario | Solver | Variable Scale | Solve Time |
|---|---|---|---|
| Supply chain resource allocation | MIP | 10K-100K | Seconds |
| Logistics route planning | Routing | 100-10K nodes | Seconds |
| Staff scheduling | CP-SAT | 1K-50K | Sec-Min |
| Inventory optimization | LP | 100K+ | Milliseconds |
| Equipment maintenance planning | CP-SAT | 1K-10K | Seconds |
#1.2 Architecture Integration
Code
┌────────────────────────────────────────┐
│ Reasoning & Decision Layer: Reasoning & Decision │
│ ┌──────────────┐ ┌───────────────┐ │
│ │ Decision │ │ Reasoning │ │
│ │ Engine │ │ Engine │ │
│ └──────┬───────┘ └──────────────┘ │
│ ┌──────┴───────────────────────┐ │
│ │ OR-Tools Solver Service │ │
│ │ ┌──────┐ ┌──────┐ ┌──────┐ │ │
│ │ │ LP │ │CP-SAT│ │Route │ │ │
│ │ └──────┘ └──────┘ └──────┘ │ │
│ └──────────────────────────────┘ │
└────────────────────────────────────────┘
#2. Four Solvers
| Solver | Variable Type | Constraint Type | Optimality | Speed |
|---|---|---|---|---|
| GLOP (LP) | Continuous | Linear | Global optimal | Very fast |
| SCIP (MIP) | Continuous+Integer | Linear | Global optimal | Fast |
| CP-SAT | Integer+Boolean | Linear+Logical | Global optimal | Medium |
| Routing | Integer | Path constraints | Near-optimal | Fast |
#3. Linear and Mixed-Integer Programming
#3.1 Resource Allocation LP
Python
from ortools.linear_solver import pywraplp
def optimize_resource_allocation(resources, tasks, costs):
solver = pywraplp.Solver.CreateSolver("GLOP")
n_resources, n_tasks = len(resources), len(tasks)
x = [[solver.NumVar(0, 1, f"x_{i}_{j}") for j in range(n_tasks)] for i in range(n_resources)]
# Each task must be fully assigned
for j in range(n_tasks):
solver.Add(sum(x[i][j] for i in range(n_resources)) == 1)
# Resource capacity constraints
for i in range(n_resources):
solver.Add(sum(x[i][j] * tasks[j]["demand"] for j in range(n_tasks)) <= resources[i]["capacity"])
solver.Minimize(sum(x[i][j] * costs[i][j] for i in range(n_resources) for j in range(n_tasks)))
status = solver.Solve()
if status == pywraplp.Solver.OPTIMAL:
return {"status": "optimal", "total_cost": solver.Objective().Value(),
"assignments": [{"resource": i, "task": j, "allocation": x[i][j].solution_value()}
for i in range(n_resources) for j in range(n_tasks) if x[i][j].solution_value() > 0.01]}
return {"status": "infeasible"}
#3.2 Facility Location MIP
Python
def optimize_facility_location(facilities, customers, fixed_costs, transport_costs):
solver = pywraplp.Solver.CreateSolver("SCIP")
n_f, n_c = len(facilities), len(customers)
y = [solver.IntVar(0, 1, f"y_{i}") for i in range(n_f)] # Open facility?
x = [[solver.NumVar(0, 1, f"x_{i}_{j}") for j in range(n_c)] for i in range(n_f)]
for j in range(n_c):
solver.Add(sum(x[i][j] for i in range(n_f)) == 1)
for i in range(n_f):
for j in range(n_c):
solver.Add(x[i][j] <= y[i])
solver.Add(sum(x[i][j] * customers[j]["demand"] for j in range(n_c)) <= facilities[i]["capacity"] * y[i])
solver.Minimize(sum(fixed_costs[i] * y[i] for i in range(n_f))
+ sum(transport_costs[i][j] * x[i][j] for i in range(n_f) for j in range(n_c)))
status = solver.Solve()
if status == pywraplp.Solver.OPTIMAL:
return {"status": "optimal", "opened": [i for i in range(n_f) if y[i].solution_value() > 0.5],
"total_cost": solver.Objective().Value()}
return {"status": "infeasible"}
#4. CP-SAT Constraint Programming
#4.1 Staff Scheduling
Python
from ortools.sat.python import cp_model
def optimize_staff_scheduling(employees, shifts, days=7):
model = cp_model.CpModel()
n_emp, n_shifts = len(employees), len(shifts)
schedule = {}
for e in range(n_emp):
for d in range(days):
for s in range(n_shifts):
schedule[(e, d, s)] = model.NewBoolVar(f"s_{e}_{d}_{s}")
# Min staff per shift
for d in range(days):
for s in range(n_shifts):
model.Add(sum(schedule[(e, d, s)] for e in range(n_emp)) >= shifts[s]["min_staff"])
# Max one shift per day per employee
for e in range(n_emp):
for d in range(days):
model.Add(sum(schedule[(e, d, s)] for s in range(n_shifts)) <= 1)
# Max work days per week
for e in range(n_emp):
model.Add(sum(schedule[(e, d, s)] for d in range(days) for s in range(n_shifts))
<= employees[e].get("max_days", 5))
# No more than 2 consecutive night shifts
night = n_shifts - 1
for e in range(n_emp):
for d in range(days - 2):
model.Add(schedule[(e, d, night)] + schedule[(e, d+1, night)] + schedule[(e, d+2, night)] <= 2)
# Maximize preference satisfaction
prefs = []
for e in range(n_emp):
for d in range(days):
for s in range(n_shifts):
p = employees[e].get("preferences", {}).get(f"{d}_{s}", 0)
prefs.append(schedule[(e, d, s)] * p)
model.Maximize(sum(prefs))
solver = cp_model.CpSolver()
solver.parameters.max_time_in_seconds = 30
solver.parameters.num_workers = 4
status = solver.Solve(model)
if status in (cp_model.OPTIMAL, cp_model.FEASIBLE):
result = [{"employee": employees[e]["name"], "day": d, "shift": shifts[s]["name"]}
for e in range(n_emp) for d in range(days) for s in range(n_shifts)
if solver.Value(schedule[(e, d, s)]) == 1]
return {"status": "optimal" if status == cp_model.OPTIMAL else "feasible",
"schedule": result, "objective": solver.ObjectiveValue()}
return {"status": "infeasible"}
#5. Route Optimization
Python
from ortools.constraint_solver import routing_enums_pb2, pywrapcp
def optimize_vehicle_routing(depot, locations, demands, vehicle_capacities, num_vehicles):
distance_matrix = compute_distance_matrix(locations)
manager = pywrapcp.RoutingIndexManager(len(locations), num_vehicles, depot)
routing = pywrapcp.RoutingModel(manager)
def distance_callback(from_idx, to_idx):
return int(distance_matrix[manager.IndexToNode(from_idx)][manager.IndexToNode(to_idx)])
transit_cb = routing.RegisterTransitCallback(distance_callback)
routing.SetArcCostEvaluatorOfAllVehicles(transit_cb)
def demand_callback(from_idx):
return demands[manager.IndexToNode(from_idx)]
demand_cb = routing.RegisterUnaryTransitCallback(demand_callback)
routing.AddDimensionWithVehicleCapacity(demand_cb, 0, vehicle_capacities, True, "Capacity")
params = pywrapcp.DefaultRoutingSearchParameters()
params.first_solution_strategy = routing_enums_pb2.FirstSolutionStrategy.PATH_CHEAPEST_ARC
params.local_search_metaheuristic = routing_enums_pb2.LocalSearchMetaheuristic.GUIDED_LOCAL_SEARCH
params.time_limit.seconds = 30
solution = routing.SolveWithParameters(params)
if solution:
routes = []
for v in range(num_vehicles):
route, idx = [], routing.Start(v)
while not routing.IsEnd(idx):
route.append(manager.IndexToNode(idx))
idx = solution.Value(routing.NextVar(idx))
route.append(manager.IndexToNode(idx))
routes.append(route)
return {"status": "solved", "routes": routes, "total_distance": solution.ObjectiveValue()}
return {"status": "no_solution"}
#6. Job Scheduling
Python
def optimize_job_shop(jobs, num_machines):
model = cp_model.CpModel()
horizon = sum(d for job in jobs for _, d in job)
all_tasks = {}
for j_id, job in enumerate(jobs):
for t_id, (machine, duration) in enumerate(job):
start = model.NewIntVar(0, horizon, f"s_{j_id}_{t_id}")
end = model.NewIntVar(0, horizon, f"e_{j_id}_{t_id}")
interval = model.NewIntervalVar(start, duration, end, f"i_{j_id}_{t_id}")
all_tasks[(j_id, t_id)] = (start, end, interval, machine)
# Precedence within each job
for j_id, job in enumerate(jobs):
for t_id in range(len(job) - 1):
model.Add(all_tasks[(j_id, t_id + 1)][0] >= all_tasks[(j_id, t_id)][1])
# No overlap on same machine
for m in range(num_machines):
model.AddNoOverlap([all_tasks[k][2] for k in all_tasks if all_tasks[k][3] == m])
makespan = model.NewIntVar(0, horizon, "makespan")
model.AddMaxEquality(makespan, [all_tasks[k][1] for k in all_tasks])
model.Minimize(makespan)
solver = cp_model.CpSolver()
solver.parameters.max_time_in_seconds = 60
status = solver.Solve(model)
if status in (cp_model.OPTIMAL, cp_model.FEASIBLE):
return {"makespan": solver.Value(makespan),
"schedule": [{"job": k[0], "task": k[1], "machine": all_tasks[k][3],
"start": solver.Value(all_tasks[k][0]), "end": solver.Value(all_tasks[k][1])} for k in all_tasks]}
return {"status": "infeasible"}
#7. Resource Allocation
Python
def optimize_budget_allocation(projects, total_budget):
solver = pywraplp.Solver.CreateSolver("GLOP")
n = len(projects)
x = [solver.NumVar(0, total_budget, f"x_{i}") for i in range(n)]
solver.Add(sum(x) <= total_budget)
for i, p in enumerate(projects):
if "min_budget" in p: solver.Add(x[i] >= p["min_budget"])
if "max_budget" in p: solver.Add(x[i] <= p["max_budget"])
solver.Maximize(sum(x[i] * projects[i]["expected_roi"] for i in range(n)))
status = solver.Solve()
if status == pywraplp.Solver.OPTIMAL:
return {"allocations": {projects[i]["name"]: x[i].solution_value() for i in range(n)}}
return {"status": "infeasible"}
#8. Ontology Integration
Python
class OntologyOptimizationService:
async def optimize(self, world_id: str, problem_type: str, params: dict) -> dict:
data = await self.load_ontology_data(world_id, problem_type)
solver_func = {"resource_allocation": optimize_resource_allocation,
"vehicle_routing": optimize_vehicle_routing,
"staff_scheduling": optimize_staff_scheduling}[problem_type]
result = await asyncio.get_event_loop().run_in_executor(self.executor, solver_func, **data, **params)
await self.store_decision_result(world_id, problem_type, result)
return result
#9. Solver Performance Tuning
| Parameter | Description | Recommended |
|---|---|---|
max_time_in_seconds | Solve time limit | 10-60s |
num_workers | Parallel solve threads | CPU cores |
relative_gap_limit | Relative gap (MIP) | 0.01 (1%) |
#10. Production Deployment
Python
class SolverService:
def __init__(self, max_workers: int = 4):
self.executor = ProcessPoolExecutor(max_workers=max_workers)
async def solve(self, problem):
return await asyncio.get_event_loop().run_in_executor(self.executor, self._sync_solve, problem)
#11. Key Takeaways
| Topic | Key Conclusion |
|---|---|
| Solver selection | LP continuous / MIP integer / CP-SAT logical / Routing paths |
| Modeling | Define variables and constraints, then set objective |
| Performance | Set time limits, accept sub-optimal solutions |
| Integration | Load data from Ontology, write results back |
| Deployment | ProcessPoolExecutor avoids GIL |
| CP-SAT | Most flexible, supports logical constraints and NoOverlap |
| VRP | Use Guided Local Search metaheuristic |
“Next up: S8-19 dives into Trino query federation, exploring cross-engine unified queries in coomia-dip.