Back to Blog

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

  1. OR-Tools in coomia-dip
  2. Four Solvers
  3. Linear and Mixed-Integer Programming
  4. CP-SAT Constraint Programming
  5. Route Optimization
  6. Job Scheduling
  7. Resource Allocation
  8. Ontology Integration
  9. Solver Performance Tuning
  10. Production Deployment
  11. Key Takeaways

#1. OR-Tools in coomia-dip

#1.1 Decision Optimization Scenarios

ScenarioSolverVariable ScaleSolve Time
Supply chain resource allocationMIP10K-100KSeconds
Logistics route planningRouting100-10K nodesSeconds
Staff schedulingCP-SAT1K-50KSec-Min
Inventory optimizationLP100K+Milliseconds
Equipment maintenance planningCP-SAT1K-10KSeconds

#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

SolverVariable TypeConstraint TypeOptimalitySpeed
GLOP (LP)ContinuousLinearGlobal optimalVery fast
SCIP (MIP)Continuous+IntegerLinearGlobal optimalFast
CP-SATInteger+BooleanLinear+LogicalGlobal optimalMedium
RoutingIntegerPath constraintsNear-optimalFast

#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

ParameterDescriptionRecommended
max_time_in_secondsSolve time limit10-60s
num_workersParallel solve threadsCPU cores
relative_gap_limitRelative 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

TopicKey Conclusion
Solver selectionLP continuous / MIP integer / CP-SAT logical / Routing paths
ModelingDefine variables and constraints, then set objective
PerformanceSet time limits, accept sub-optimal solutions
IntegrationLoad data from Ontology, write results back
DeploymentProcessPoolExecutor avoids GIL
CP-SATMost flexible, supports logical constraints and NoOverlap
VRPUse Guided Local Search metaheuristic

Next up: S8-19 dives into Trino query federation, exploring cross-engine unified queries in coomia-dip.