""" OR-Tools CP-SAT single-machine (or multi-machine) scheduling. Input: list of tasks with duration; output: start times and makespan. """ from ortools.sat.python import cp_model from typing import List, Dict, Any, Optional def solve_single_machine(tasks: List[Dict[str, Any]], horizon: int = 10000) -> Dict[str, Any]: """ tasks: [ {"id": "A", "duration": 2}, ... ] Returns: {"schedule": [ {"id": "A", "start": 0, "end": 2} ], "makespan": int } or {"error": "..."} """ model = cp_model.CpModel() starts = {} ends = {} intervals = [] for t in tasks: tid = t["id"] dur = int(t.get("duration", 1)) start = model.NewIntVar(0, horizon, f"s_{tid}") end = model.NewIntVar(0, horizon, f"e_{tid}") interval = model.NewIntervalVar(start, dur, end, f"i_{tid}") starts[tid] = start ends[tid] = end intervals.append(interval) model.AddNoOverlap(intervals) makespan = model.NewIntVar(0, horizon, "makespan") for tid, e in ends.items(): model.Add(makespan >= e) model.Minimize(makespan) solver = cp_model.CpSolver() status = solver.Solve(model) if status != cp_model.OPTIMAL and status != cp_model.FEASIBLE: return {"error": "No solution found", "status": str(status)} schedule = [] for t in tasks: tid = t["id"] start = solver.Value(starts[tid]) end = solver.Value(ends[tid]) schedule.append({"id": tid, "start": start, "end": end}) return {"schedule": schedule, "makespan": int(solver.ObjectiveValue())}