// get solver from array of interval variables private static Solver GetSolver(IntervalVar[] vars) { if (vars == null || vars.Length <= 0) throw new ArgumentException("Array <vars> cannot be null or empty"); return vars[0].solver(); }
static void Main() { CpModel model = new CpModel(); int horizon = 100; // C# code supports constant of affine expressions. IntVar start_var = model.NewIntVar(0, horizon, "start"); IntVar end_var = model.NewIntVar(0, horizon, "end"); BoolVar presence_var = model.NewBoolVar("presence"); IntervalVar interval = model.NewOptionalIntervalVar(start_var, 10, end_var + 2, presence_var, "interval"); Console.WriteLine(interval); // If the size is fixed, a simpler version uses the start expression, the size and the // literal. IntervalVar fixedSizeIntervalVar = model.NewOptionalFixedSizeIntervalVar(start_var, 10, presence_var, "fixed_size_interval_var"); Console.WriteLine(fixedSizeIntervalVar); // A fixed interval can be created using the same API. IntervalVar fixedInterval = model.NewOptionalFixedSizeIntervalVar(5, 10, presence_var, "fixed_interval"); Console.WriteLine(fixedInterval); }
public IntervalVar[] MakeFixedDurationIntervalVarArray(int count, int[] start_min, int[] start_max, int[] duration, bool optional, string name) { IntervalVar[] array = new IntervalVar[count]; for (int i = 0; i < count; ++i) { array[i] = MakeFixedDurationIntervalVar(start_min[i], start_max[i], duration[i], optional, name + i); } return(array); }
static void Main() { CpModel model = new CpModel(); int horizon = 100; IntVar start_var = model.NewIntVar(0, horizon, "start"); // C# code supports IntVar or integer constants in intervals. int duration = 10; IntVar end_var = model.NewIntVar(0, horizon, "end"); IntervalVar interval = model.NewIntervalVar(start_var, duration, end_var, "interval"); }
public IntervalVar[] MakeFixedDurationIntervalVarArray(int count, long start_min, long start_max, long duration, bool optional) { IntervalVar[] array = new IntervalVar[count]; for (int i = 0; i < count; ++i) { array[i] = MakeFixedDurationIntervalVar(start_min, start_max, duration, optional, ""); } return(array); }
static void Main() { InitTaskList(); int taskCount = GetTaskCount(); CpModel model = new CpModel(); IntervalVar[] tasks = new IntervalVar[taskCount]; BoolVar[] taskChoosed = new BoolVar[taskCount]; IntVar[] allEnds = new IntVar[GetEndTaskCount()]; int endJobCounter = 0; foreach (Job j in myJobList) { BoolVar[] tmp = new BoolVar[j.AlternativeTasks.Count]; int i = 0; foreach (Task t in j.AlternativeTasks) { long ti = taskIndexes[t.Name]; taskChoosed[ti] = model.NewBoolVar(t.Name + "_choose"); tmp[i++] = taskChoosed[ti]; IntVar start = model.NewIntVar(0, 10000, t.Name + "_start"); IntVar end = model.NewIntVar(0, 10000, t.Name + "_end"); tasks[ti] = model.NewIntervalVar(start, t.Duration, end, t.Name + "_interval"); if (j.Successor == null) { allEnds[endJobCounter++] = end; } if (!tasksToEquipment.ContainsKey(t.Equipment)) { tasksToEquipment[t.Equipment] = new List <IntervalVar>(); } tasksToEquipment[t.Equipment].Add(tasks[ti]); } model.AddExactlyOne(tmp); } foreach (KeyValuePair <long, List <IntervalVar> > pair in tasksToEquipment) { model.AddNoOverlap(pair.Value); } IntVar makespan = model.NewIntVar(0, 100000, "makespan"); model.AddMaxEquality(makespan, allEnds); model.Minimize(makespan); // Create the solver. CpSolver solver = new CpSolver(); // Solve the problem. solver.Solve(model); Console.WriteLine(solver.ResponseStats()); }
static void Main() { CpModel model = new CpModel(); // Three weeks. int horizon = 21; // Task 0, duration 2. IntVar start_0 = model.NewIntVar(0, horizon, "start_0"); int duration_0 = 2; IntVar end_0 = model.NewIntVar(0, horizon, "end_0"); IntervalVar task_0 = model.NewIntervalVar(start_0, duration_0, end_0, "task_0"); // Task 1, duration 4. IntVar start_1 = model.NewIntVar(0, horizon, "start_1"); int duration_1 = 4; IntVar end_1 = model.NewIntVar(0, horizon, "end_1"); IntervalVar task_1 = model.NewIntervalVar(start_1, duration_1, end_1, "task_1"); // Task 2, duration 3. IntVar start_2 = model.NewIntVar(0, horizon, "start_2"); int duration_2 = 3; IntVar end_2 = model.NewIntVar(0, horizon, "end_2"); IntervalVar task_2 = model.NewIntervalVar(start_2, duration_2, end_2, "task_2"); // Weekends. IntervalVar weekend_0 = model.NewIntervalVar(5, 2, 7, "weekend_0"); IntervalVar weekend_1 = model.NewIntervalVar(12, 2, 14, "weekend_1"); IntervalVar weekend_2 = model.NewIntervalVar(19, 2, 21, "weekend_2"); // No Overlap constraint. model.AddNoOverlap(new IntervalVar[] { task_0, task_1, task_2, weekend_0, weekend_1, weekend_2 }); // Makespan objective. IntVar obj = model.NewIntVar(0, horizon, "makespan"); model.AddMaxEquality(obj, new IntVar[] { end_0, end_1, end_2 }); model.Minimize(obj); // Creates a solver and solves the model. CpSolver solver = new CpSolver(); CpSolverStatus status = solver.Solve(model); if (status == CpSolverStatus.Optimal) { Console.WriteLine("Optimal Schedule Length: " + solver.ObjectiveValue); Console.WriteLine("Task 0 starts at " + solver.Value(start_0)); Console.WriteLine("Task 1 starts at " + solver.Value(start_1)); Console.WriteLine("Task 2 starts at " + solver.Value(start_2)); } }
public IntervalVar[] MakeFixedDurationIntervalVarArray(IntVar[] starts, long[] durations, string name) { int count = starts.Length; IntervalVar[] array = new IntervalVar[count]; for (int i = 0; i < count; ++i) { array[i] = MakeFixedDurationIntervalVar(starts[i], durations[i], name + i); } return(array); }
public void TestInterval() { Console.WriteLine("TestInterval test"); CpModel model = new CpModel(); IntVar v = model.NewIntVar(-10, 10, "v"); IntervalVar i = model.NewFixedSizeIntervalVar(v, 3, "i"); Assert.Equal("v", i.StartExpr().ShortString()); Assert.Equal("3", i.SizeExpr().ShortString()); Assert.Equal("(v + 3)", i.EndExpr().ShortString()); }
static void OptionalIntervalSample() { CpModel model = new CpModel(); int horizon = 100; IntVar start_var = model.NewIntVar(0, horizon, "start"); // C# code supports IntVar or integer constants in intervals. int duration = 10; IntVar end_var = model.NewIntVar(0, horizon, "end"); IntVar presence_var = model.NewBoolVar("presence"); IntervalVar interval = model.NewOptionalIntervalVar( start_var, duration, end_var, presence_var, "interval"); }
public Task(IntVar s, IntVar e, IntervalVar i, int oper, List <string> lots, string ent, string recipe, int paket, int prio, int maxOperAgo, int duration) { start = s; end = e; interval = i; operation = oper; this.lots = lots; entity = ent; this.recipe = recipe; this.paket = paket; priority = prio; sortPriority = 0; this.maxOperAgo = maxOperAgo; this.duration = duration; }
public static void JobShopCp(List <Job> jobs, int machines) { CpModel model = new CpModel(); int maxValue = 0; foreach (var job in jobs) { maxValue += job.Tasks.Sum(j => j.Duration); } List <List <IntervalVar> > intervals = new List <List <IntervalVar> >(jobs.Count); List <List <IntVar> > starts = new List <List <IntVar> >(jobs.Count); List <List <IntVar> > ends = new List <List <IntVar> >(jobs.Count); List <List <IntervalVar> > machinesIntervals = new List <List <IntervalVar> >(); List <List <IntVar> > machinesStarts = new List <List <IntVar> >(); for (int i = 0; i < machines; i++) { machinesIntervals.Add(new List <IntervalVar>()); machinesStarts.Add(new List <IntVar>()); } foreach (var job in jobs) { starts.Add(new List <IntVar>()); ends.Add(new List <IntVar>()); intervals.Add(new List <IntervalVar>()); foreach (var task in job.Tasks) { IntVar start = model.NewIntVar(0, maxValue, job.Name + task.Name); IntVar end = model.NewIntVar(0, maxValue, job.Name + task.Name); IntervalVar oneTask = model.NewIntervalVar(start, task.Duration, end, job.Name + task.Name); intervals[job.JobId].Add(oneTask); starts[job.JobId].Add(start); ends[job.JobId].Add(end); machinesIntervals[task.Machine].Add(oneTask); machinesStarts[task.Machine].Add(start); } } for (int j = 0; j < jobs.Count; ++j) { for (int t = 0; t < jobs[j].Tasks.Count - 1; ++t) { model.Add(ends[j][t] <= starts[j][t + 1]); } } for (int machineId = 0; machineId < machines; ++machineId) { model.AddNoOverlap(machinesIntervals[machineId].ToArray()); } IntVar[] allEnds = new IntVar[jobs.Count]; for (int i = 0; i < jobs.Count; i++) { allEnds[i] = ends[i].Last(); } IntVar makespan = model.NewIntVar(0, maxValue, "makespan"); model.AddMaxEquality(makespan, allEnds); model.Minimize(makespan); CpSolver solver = new CpSolver(); solver.StringParameters = "max_time_in_seconds:30.0"; CpSolverStatus solverStatus = solver.Solve(model); if (solverStatus != CpSolverStatus.Optimal) { Console.WriteLine("Solver didn’t find optimal solution!"); } Console.WriteLine("Objective value = " + solver.Value(makespan)); }
public IntervalVar[] MakeFixedDurationIntervalVarArray(int count, int[] start_min, int[] start_max, int[] duration, bool optional, string name) { IntervalVar[] array = new IntervalVar[count]; for (int i = 0; i < count; ++i) { array[i] = MakeFixedDurationIntervalVar(start_min[i], start_max[i], duration[i], optional, name + i); } return array; }
static void Main() { CpModel model = new CpModel(); // Three weeks. int horizon = 100; int num_tasks = 4; IntVar[] starts = new IntVar[num_tasks]; IntVar[] ends = new IntVar[num_tasks]; IntervalVar[] intervals = new IntervalVar[num_tasks]; ILiteral[] presences = new ILiteral[num_tasks]; IntVar[] ranks = new IntVar[num_tasks]; IntVar true_var = model.NewConstant(1); // Creates intervals, half of them are optional. for (int t = 0; t < num_tasks; ++t) { starts[t] = model.NewIntVar(0, horizon, String.Format("start_{0}", t)); int duration = t + 1; ends[t] = model.NewIntVar(0, horizon, String.Format("end_{0}", t)); if (t < num_tasks / 2) { intervals[t] = model.NewIntervalVar(starts[t], duration, ends[t], String.Format("interval_{0}", t)); presences[t] = true_var; } else { presences[t] = model.NewBoolVar(String.Format("presence_{0}", t)); intervals[t] = model.NewOptionalIntervalVar( starts[t], duration, ends[t], presences[t], String.Format("o_interval_{0}", t)); } // Ranks = -1 if and only if the tasks is not performed. ranks[t] = model.NewIntVar(-1, num_tasks - 1, String.Format("rank_{0}", t)); } // Adds NoOverlap constraint. model.AddNoOverlap(intervals); // Adds ranking constraint. RankTasks(model, starts, presences, ranks); // Adds a constraint on ranks. model.Add(ranks[0] < ranks[1]); // Creates makespan variable. IntVar makespan = model.NewIntVar(0, horizon, "makespan"); for (int t = 0; t < num_tasks; ++t) { model.Add(ends[t] <= makespan).OnlyEnforceIf(presences[t]); } // Minimizes makespan - fixed gain per tasks performed. // As the fixed cost is less that the duration of the last interval, // the solver will not perform the last interval. IntVar[] presences_as_int_vars = new IntVar[num_tasks]; for (int t = 0; t < num_tasks; ++t) { presences_as_int_vars[t] = (IntVar)presences[t]; } model.Minimize(2 * makespan - 7 * presences_as_int_vars.Sum()); // Creates a solver and solves the model. CpSolver solver = new CpSolver(); CpSolverStatus status = solver.Solve(model); if (status == CpSolverStatus.Optimal) { Console.WriteLine(String.Format("Optimal cost: {0}", solver.ObjectiveValue)); Console.WriteLine(String.Format("Makespan: {0}", solver.Value(makespan))); for (int t = 0; t < num_tasks; ++t) { if (solver.BooleanValue(presences[t])) { Console.WriteLine(String.Format( "Task {0} starts at {1} with rank {2}", t, solver.Value(starts[t]), solver.Value(ranks[t]))); } else { Console.WriteLine(String.Format( "Task {0} in not performed and ranked at {1}", t, solver.Value(ranks[t]))); } } } else { Console.WriteLine( String.Format("Solver exited with nonoptimal status: {0}", status)); } }
static void Main() { CpModel model = new CpModel(); int[,] jobs = new[, ] { { 3, 3 }, { 2, 5 }, { 1, 3 }, { 3, 7 }, { 7, 3 }, { 2, 2 }, { 2, 2 }, { 5, 5 }, { 10, 2 }, { 4, 3 }, { 2, 6 }, { 1, 2 }, { 6, 8 }, { 4, 5 }, { 3, 7 } }; int max_length = 10; int num_jobs = jobs.GetLength(0); var all_jobs = Enumerable.Range(0, num_jobs); int horizon = 0; foreach (int j in all_jobs) { horizon += jobs[j, 0]; } List <IntervalVar> intervals = new List <IntervalVar>(); List <IntervalVar> intervals0 = new List <IntervalVar>(); List <IntervalVar> intervals1 = new List <IntervalVar>(); List <IntVar> performed = new List <IntVar>(); List <IntVar> starts = new List <IntVar>(); List <IntVar> ends = new List <IntVar>(); List <int> demands = new List <int>(); foreach (int i in all_jobs) { // Create main interval. IntVar start = model.NewIntVar(0, horizon, String.Format("start_{0}", i)); int duration = jobs[i, 0]; IntVar end = model.NewIntVar(0, horizon, String.Format("end_{0}", i)); IntervalVar interval = model.NewIntervalVar(start, duration, end, String.Format("interval_{0}", i)); starts.Add(start); intervals.Add(interval); ends.Add(end); demands.Add(jobs[i, 1]); IntVar performed_on_m0 = model.NewBoolVar(String.Format("perform_{0}_on_m0", i)); performed.Add(performed_on_m0); // Create an optional copy of interval to be executed on machine 0. IntVar start0 = model.NewIntVar(0, horizon, String.Format("start_{0}_on_m0", i)); IntVar end0 = model.NewIntVar(0, horizon, String.Format("end_{0}_on_m0", i)); IntervalVar interval0 = model.NewOptionalIntervalVar(start0, duration, end0, performed_on_m0, String.Format("interval_{0}_on_m0", i)); intervals0.Add(interval0); // Create an optional copy of interval to be executed on machine 1. IntVar start1 = model.NewIntVar(0, horizon, String.Format("start_{0}_on_m1", i)); IntVar end1 = model.NewIntVar(0, horizon, String.Format("end_{0}_on_m1", i)); IntervalVar interval1 = model.NewOptionalIntervalVar(start1, duration, end1, performed_on_m0.Not(), String.Format("interval_{0}_on_m1", i)); intervals1.Add(interval1); // We only propagate the constraint if the tasks is performed on the // machine. model.Add(start0 == start).OnlyEnforceIf(performed_on_m0); model.Add(start1 == start).OnlyEnforceIf(performed_on_m0.Not()); } // Max Length constraint (modeled as a cumulative) model.AddCumulative(intervals, demands, max_length); // Choose which machine to perform the jobs on. model.AddNoOverlap(intervals0); model.AddNoOverlap(intervals1); // Objective variable. IntVar makespan = model.NewIntVar(0, horizon, "makespan"); model.AddMaxEquality(makespan, ends); model.Minimize(makespan); // Symmetry breaking. model.Add(performed[0] == 0); // Creates the solver and solve. CpSolver solver = new CpSolver(); solver.Solve(model); // Output solution. Console.WriteLine("Solution"); Console.WriteLine(" - makespan = " + solver.ObjectiveValue); foreach (int i in all_jobs) { long performed_machine = 1 - solver.Value(performed[i]); long start = solver.Value(starts[i]); Console.WriteLine(String.Format(" - Job {0} starts at {1} on machine {2}", i, start, performed_machine)); } Console.WriteLine("Statistics"); Console.WriteLine(" - conflicts : " + solver.NumConflicts()); Console.WriteLine(" - branches : " + solver.NumBranches()); Console.WriteLine(" - wall time : " + solver.WallTime() + " ms"); }
// [END assigned_task] public static void Main(String[] args) { // [START data] var allJobs = new[] { new[] { // job0 new { machine = 0, duration = 3 }, // task0 new { machine = 1, duration = 2 }, // task1 new { machine = 2, duration = 2 }, // task2 } .ToList(), new[] { // job1 new { machine = 0, duration = 2 }, // task0 new { machine = 2, duration = 1 }, // task1 new { machine = 1, duration = 4 }, // task2 } .ToList(), new[] { // job2 new { machine = 1, duration = 4 }, // task0 new { machine = 2, duration = 3 }, // task1 } .ToList(), } .ToList(); int numMachines = 0; foreach (var job in allJobs) { foreach (var task in job) { numMachines = Math.Max(numMachines, 1 + task.machine); } } int[] allMachines = Enumerable.Range(0, numMachines).ToArray(); // Computes horizon dynamically as the sum of all durations. int horizon = 0; foreach (var job in allJobs) { foreach (var task in job) { horizon += task.duration; } } // [END data] // Creates the model. // [START model] CpModel model = new CpModel(); // [END model] // [START variables] Dictionary <Tuple <int, int>, Tuple <IntVar, IntVar, IntervalVar> > allTasks = new Dictionary <Tuple <int, int>, Tuple <IntVar, IntVar, IntervalVar> >(); // (start, end, duration) Dictionary <int, List <IntervalVar> > machineToIntervals = new Dictionary <int, List <IntervalVar> >(); for (int jobID = 0; jobID < allJobs.Count(); ++jobID) { var job = allJobs[jobID]; for (int taskID = 0; taskID < job.Count(); ++taskID) { var task = job[taskID]; String suffix = $"_{jobID}_{taskID}"; IntVar start = model.NewIntVar(0, horizon, "start" + suffix); IntVar end = model.NewIntVar(0, horizon, "end" + suffix); IntervalVar interval = model.NewIntervalVar(start, task.duration, end, "interval" + suffix); var key = Tuple.Create(jobID, taskID); allTasks[key] = Tuple.Create(start, end, interval); if (!machineToIntervals.ContainsKey(task.machine)) { machineToIntervals.Add(task.machine, new List <IntervalVar>()); } machineToIntervals[task.machine].Add(interval); } } // [END variables] // [START constraints] // Create and add disjunctive constraints. foreach (int machine in allMachines) { model.AddNoOverlap(machineToIntervals[machine]); } // Precedences inside a job. for (int jobID = 0; jobID < allJobs.Count(); ++jobID) { var job = allJobs[jobID]; for (int taskID = 0; taskID < job.Count() - 1; ++taskID) { var key = Tuple.Create(jobID, taskID); var nextKey = Tuple.Create(jobID, taskID + 1); model.Add(allTasks[nextKey].Item1 >= allTasks[key].Item2); } } // [END constraints] // [START objective] // Makespan objective. IntVar objVar = model.NewIntVar(0, horizon, "makespan"); List <IntVar> ends = new List <IntVar>(); for (int jobID = 0; jobID < allJobs.Count(); ++jobID) { var job = allJobs[jobID]; var key = Tuple.Create(jobID, job.Count() - 1); ends.Add(allTasks[key].Item2); } model.AddMaxEquality(objVar, ends); model.Minimize(objVar); // [END objective] // Solve // [START solve] CpSolver solver = new CpSolver(); CpSolverStatus status = solver.Solve(model); Console.WriteLine($"Solve status: {status}"); // [END solve] // [START print_solution] if (status == CpSolverStatus.Optimal || status == CpSolverStatus.Feasible) { Console.WriteLine("Solution:"); Dictionary <int, List <AssignedTask> > assignedJobs = new Dictionary <int, List <AssignedTask> >(); for (int jobID = 0; jobID < allJobs.Count(); ++jobID) { var job = allJobs[jobID]; for (int taskID = 0; taskID < job.Count(); ++taskID) { var task = job[taskID]; var key = Tuple.Create(jobID, taskID); int start = (int)solver.Value(allTasks[key].Item1); if (!assignedJobs.ContainsKey(task.machine)) { assignedJobs.Add(task.machine, new List <AssignedTask>()); } assignedJobs[task.machine].Add(new AssignedTask(jobID, taskID, start, task.duration)); } } // Create per machine output lines. String output = ""; foreach (int machine in allMachines) { // Sort by starting time. assignedJobs[machine].Sort(); String solLineTasks = $"Machine {machine}: "; String solLine = " "; foreach (var assignedTask in assignedJobs[machine]) { String name = $"job_{assignedTask.jobID}_task_{assignedTask.taskID}"; // Add spaces to output to align columns. solLineTasks += $"{name,-15}"; String solTmp = $"[{assignedTask.start},{assignedTask.start+assignedTask.duration}]"; // Add spaces to output to align columns. solLine += $"{solTmp,-15}"; } output += solLineTasks + "\n"; output += solLine + "\n"; } // Finally print the solution found. Console.WriteLine($"Optimal Schedule Length: {solver.ObjectiveValue}"); Console.WriteLine($"\n{output}"); } else { Console.WriteLine("No solution found."); } // [END print_solution] // [START statistics] Console.WriteLine("Statistics"); Console.WriteLine($" conflicts: {solver.NumConflicts()}"); Console.WriteLine($" branches : {solver.NumBranches()}"); Console.WriteLine($" wall time: {solver.WallTime()}s"); // [END statistics] }
private void Model() { /* Building basic task data structures */ for (int i = 0; i < tasks.Length; i++) { /* Create a new set of possible IntervalVars & IntVar to decide * which one (and only 1) is performed */ taskStructures[i] = new TaskAlternative(tasks[i]); /* Container to use when posting constraints */ location2Task[tasks[i].LocationId][tasks[i].TaskPosition] = taskStructures[i]; /* Get task type */ int taskType = tasks[i].TaskType; /* Possible tool for this task */ List <Tool> tools = taskType2Tool[taskType]; bool optional = tools.Count > 1; /* List of boolean variables. If performedOnTool[t] == true then * the task is performed on tool t */ List <IntVar> performedOnTool = new List <IntVar>(); for (int t = 0; t < tools.Count; t++) { /* Creating an IntervalVar. If tools.Count > 1 the intervalVar * is *OPTIONAL* */ int toolId = tools[t].Id; Debug.Assert(tasks[i].Durations.ContainsKey(toolId)); int duration = tasks[i].Durations[toolId]; string name = "J " + tasks[i].Id + " [" + toolId + "]"; IntervalVar intervalVar; if (taskType == factoryData.Inspection) { /* We set a 0 time if the task is an inspection */ duration = 0; intervalVar = solver.MakeFixedDurationIntervalVar(0, horizon, duration, optional, name); IntVar start = intervalVar.SafeStartExpr(-1).Var(); intervalVar.SafeStartExpr(-1).Var().SetValues(factoryData.InspectionStarts); } else { intervalVar = solver.MakeFixedDurationIntervalVar(0, horizon, duration, optional, name); } taskStructures[i].Intervals.Add(intervalVar); tool2Task[toolId].Add(intervalVar); toolIntervalVar2TaskId[toolId].Add(i); /* Collecting all the bool vars, even if they are optional */ performedOnTool.Add(intervalVar.PerformedExpr().Var()); } /* Linking the bool var to a single integer variable: */ /* if alternativeToolVar == t <=> performedOnTool[t] == true */ string alternativeName = "J " + tasks[i].Id; IntVar alternativeToolVar = solver.MakeIntVar(0, tools.Count - 1, alternativeName); taskStructures[i].ToolVar = alternativeToolVar; solver.Add(solver.MakeMapDomain(alternativeToolVar, performedOnTool.ToArray())); Debug.Assert(performedOnTool.ToArray().Length == alternativeToolVar.Max() + 1); selectedTool.Add(alternativeToolVar); } /* Creates precedences on a work Location in order to enforce a * fully ordered set within the same location */ for (int d = 0; d < location2Task.Length; d++) { for (int i = 0; i < location2Task[d].Length - 1; i++) { TaskAlternative task1 = location2Task[d][i]; TaskAlternative task2 = location2Task[d][i + 1]; /* task1 must end before task2 starts */ /* Adding precedence for each possible alternative pair */ for (int t1 = 0; t1 < task1.Intervals.Count(); t1++) { IntervalVar task1Alternative = task1.Intervals[t1]; for (int t2 = 0; t2 < task2.Intervals.Count(); t2++) { IntervalVar task2Alternative = task2.Intervals[t2]; Constraint precedence = solver.MakeIntervalVarRelation( task2Alternative, Solver.STARTS_AFTER_END, task1Alternative); solver.Add(precedence); } } } } /* Adds disjunctive constraints on unary resources, and creates * sequence variables. */ for (int t = 0; t < factoryData.NbTools; t++) { string name = "Tool " + t; if (!factoryData.Tools[t].CanPerformTaskType(factoryData.Inspection)) { DisjunctiveConstraint ct = solver.MakeDisjunctiveConstraint(tool2Task[t].ToArray(), name); solver.Add(ct); allToolSequences[t] = ct.SequenceVar(); } PostTransitionTimeConstraints(t, true); } /* Collecting all tasks end for makespan objective function */ List <IntVar> intervalEnds = new List <IntVar>(); for (int i = 0; i < tasks.Length; i++) { foreach (IntervalVar var in taskStructures[i].Intervals) { intervalEnds.Add(var.SafeEndExpr(-1).Var()); } } /* Objective: minimize the makespan (maximum end times of all tasks) */ makespan = solver.MakeMax(intervalEnds.ToArray()).Var(); objective = solver.MakeMinimize(makespan, 1); }
static void Main() { int[,] durations = new int[, ] { { 1, 3, 6, 7, 3, 6 }, { 8, 5, 10, 10, 10, 4 }, { 5, 4, 8, 9, 1, 7 }, { 5, 5, 5, 3, 8, 9 }, { 9, 3, 5, 4, 3, 1 }, { 3, 3, 9, 10, 4, 1 } }; int[,] machines = new int[, ] { { 2, 0, 1, 3, 5, 4 }, { 1, 2, 4, 5, 0, 3 }, { 2, 3, 5, 0, 1, 4 }, { 1, 0, 2, 3, 4, 5 }, { 2, 1, 4, 5, 0, 3 }, { 1, 3, 5, 0, 4, 2 } }; int num_jobs = durations.GetLength(0); int num_machines = durations.GetLength(1); var all_jobs = Enumerable.Range(0, num_jobs); var all_machines = Enumerable.Range(0, num_machines); int horizon = 0; foreach (int j in all_jobs) { foreach (int m in all_machines) { horizon += durations[j, m]; } } // Creates the model. CpModel model = new CpModel(); // Creates jobs. Task[,] all_tasks = new Task[num_jobs, num_machines]; foreach (int j in all_jobs) { foreach (int m in all_machines) { IntVar start_var = model.NewIntVar(0, horizon, String.Format("start_{0}_{1}", j, m)); int duration = durations[j, m]; IntVar end_var = model.NewIntVar(0, horizon, String.Format("end_{0}_{1}", j, m)); IntervalVar interval_var = model.NewIntervalVar(start_var, duration, end_var, String.Format("interval_{0}_{1}", j, m)); all_tasks[j, m] = new Task(start_var, end_var, interval_var); } } // Create disjuctive constraints. List <IntervalVar>[] machine_to_jobs = new List <IntervalVar> [num_machines]; foreach (int m in all_machines) { machine_to_jobs[m] = new List <IntervalVar>(); } foreach (int j in all_jobs) { foreach (int m in all_machines) { machine_to_jobs[machines[j, m]].Add(all_tasks[j, m].interval); } } foreach (int m in all_machines) { model.AddNoOverlap(machine_to_jobs[m]); } // Precedences inside a job. foreach (int j in all_jobs) { for (int k = 0; k < num_machines - 1; ++k) { model.Add(all_tasks[j, k + 1].start >= all_tasks[j, k].end); } } // Makespan objective. IntVar[] all_ends = new IntVar[num_jobs]; foreach (int j in all_jobs) { all_ends[j] = all_tasks[j, num_machines - 1].end; } IntVar makespan = model.NewIntVar(0, horizon, "makespan"); model.AddMaxEquality(makespan, all_ends); model.Minimize(makespan); Console.WriteLine(model.ModelStats()); // Creates the solver and solve. CpSolver solver = new CpSolver(); // Display a few solutions picked at random. solver.Solve(model); // Statistics. Console.WriteLine(solver.ResponseStats()); }
public void RunJobShopScheduling(String solverType) { Solver solver = new Solver(solverType); if (solver == null) { Console.WriteLine("JobShop failed to create a solver " + solverType); return; } // All tasks Dictionary <string, IntervalVar> allTasks = new Dictionary <string, IntervalVar>(); // Creates jobs for (int i = 0; i < allJobs.Count; i++) { for (int j = 0; j < machines.ElementAt(i).Count; j++) { IntervalVar oneTask = solver.MakeFixedDurationIntervalVar(0, horizon, processingTimes.ElementAt(i).ElementAt(j), false, "Job_" + i + "_" + j); //Console.WriteLine("Job_" + i + "_" + j); allTasks.Add("Job_" + i + "_" + j, oneTask); } } // Create sequence variables and add disjuctive constraints List <SequenceVar> allSequences = new List <SequenceVar>(); foreach (var machine in allMachines) { List <IntervalVar> machinesJobs = new List <IntervalVar>(); for (int i = 0; i < allJobs.Count; i++) { for (int k = 0; k < machines.ElementAt(i).Count; k++) { if (machines.ElementAt(i).ElementAt(k) == machine) { machinesJobs.Add(allTasks["Job_" + i + "_" + k]); } } } DisjunctiveConstraint disj = solver.MakeDisjunctiveConstraint(machinesJobs.ToArray(), "machine " + machine); allSequences.Add(disj.SequenceVar()); solver.Add(disj); } // Add conjunctive constraints foreach (var job in allJobs) { for (int j = 0; j < machines.ElementAt(job).Count - 1; j++) { solver.Add(allTasks["Job_" + job + "_" + (j + 1)].StartsAfterEnd(allTasks["Job_" + job + "_" + j])); } } // Set the objective IntVar[] allEnds = new IntVar[jobsCount]; for (int i = 0; i < allJobs.Count; i++) { allEnds[i] = allTasks["Job_" + i + "_" + (machines.ElementAt(i).Count - 1)].EndExpr().Var(); } // Objective: minimize the makespan (maximum end times of all tasks) // of the problem. IntVar objectiveVar = solver.MakeMax(allEnds).Var(); OptimizeVar objectiveMonitor = solver.MakeMinimize(objectiveVar, 1); // Create search phases DecisionBuilder sequencePhase = solver.MakePhase(allSequences.ToArray(), Solver.SEQUENCE_DEFAULT); DecisionBuilder varsPhase = solver.MakePhase(objectiveVar, Solver.CHOOSE_FIRST_UNBOUND, Solver.ASSIGN_MIN_VALUE); // The main decision builder (ranks all tasks, then fixes the // objectiveVariable). DecisionBuilder mainPhase = solver.Compose(sequencePhase, varsPhase); SolutionCollector collector = solver.MakeLastSolutionCollector(); collector.Add(allSequences.ToArray()); collector.Add(objectiveVar); foreach (var i in allMachines) { SequenceVar sequence = allSequences.ElementAt(i); long sequenceCount = sequence.Size(); for (int j = 0; j < sequenceCount; j++) { IntervalVar t = sequence.Interval(j); collector.Add(t.StartExpr().Var()); collector.Add(t.EndExpr().Var()); } } // Search. bool solutionFound = solver.Solve(mainPhase, null, objectiveMonitor, null, collector); if (solutionFound) { //The index of the solution from the collector const int SOLUTION_INDEX = 0; Assignment solution = collector.Solution(SOLUTION_INDEX); string solLine = ""; string solLineTasks = ""; Console.WriteLine("Time Intervals for Tasks\n"); List <List <TimeSpan> > tuplesSolution = new List <List <TimeSpan> >(); for (int m = 0; m < this.machinesCount; m++) { //Console.WriteLine("MachineCount: " + this.machinesCount); solLine = "Machine " + m + " :"; solLineTasks = "Machine " + m + ": "; SequenceVar seq = allSequences.ElementAt(m); int[] storedSequence = collector.ForwardSequence(SOLUTION_INDEX, seq); foreach (int taskIndex in storedSequence) { //Console.WriteLine("taskIndex: " + taskIndex); IntervalVar task = seq.Interval(taskIndex); solLineTasks += task.Name() + " "; //Console.WriteLine("Len: " + storedSequence.Length); } // First GreenTime //TimeSpan timeToAdd = tuplesSolution.First().Last(); TimeSpan timeEndBucket = this.bucketInfo.EndBucket; TimeSpan timeStartBucket = this.bucketInfo.StartBucket; int solutionSize = tuplesSolution.Count; bool isEnd = false; List <int> list_id = jobIds.ElementAt(m); // Adding GreenTime to Solution while (timeStartBucket.CompareTo(timeEndBucket) < 0) { foreach (int taskIndex in storedSequence) { IntervalVar task = seq.Interval(taskIndex); var startValue = TimeSpan.FromSeconds(collector.Value(0, task.StartExpr().Var())); var endValue = TimeSpan.FromSeconds(collector.Value(0, task.EndExpr().Var())); TimeSpan greenTime = endValue.Subtract(startValue); TimeSpan timeEnd; timeEnd = timeStartBucket.Add(greenTime); List <TimeSpan> tuple = new List <TimeSpan>(); tuple.Add(timeStartBucket); if (timeEndBucket.CompareTo(timeEnd) < 0) { timeEnd = timeEndBucket; isEnd = true; } tuple.Add(timeEnd); tuplesSolution.Add(tuple); if (taskIndex + 1 < list_id.Count() && list_id.ElementAt(taskIndex) == list_id.ElementAt(taskIndex + 1)) { timeStartBucket = timeStartBucket.Add(TimeSpan.FromSeconds(this.cycleTime)); } else { timeStartBucket = timeEnd; } if (isEnd) { break; } } } // // Saving the Solution to a XML file // JobShop.save(m, tuplesSolution); //solLine += "\n"; //solLineTasks += "\n"; //Console.WriteLine(solLineTasks); //Console.WriteLine(solLine); } } else { Console.WriteLine("No solution found!"); } }
public static void Main(String[] args) { InitTaskList(); Solver solver = new Solver("Jobshop"); // ----- Creates all Intervals and vars ----- // All tasks List <IntervalVar> allTasks = new List <IntervalVar>(); // Stores all tasks attached interval variables per job. List <List <IntervalVar> > jobsToTasks = new List <List <IntervalVar> >(jobsCount); // machinesToTasks stores the same interval variables as above, but // grouped my machines instead of grouped by jobs. List <List <IntervalVar> > machinesToTasks = new List <List <IntervalVar> >(machinesCount); for (int i = 0; i < machinesCount; i++) { machinesToTasks.Add(new List <IntervalVar>()); } // Creates all individual interval variables. foreach (List <Task> job in myJobList) { jobsToTasks.Add(new List <IntervalVar>()); foreach (Task task in job) { IntervalVar oneTask = solver.MakeFixedDurationIntervalVar( 0, horizon, task.Duration, false, task.Name); jobsToTasks[task.JobId].Add(oneTask); allTasks.Add(oneTask); machinesToTasks[task.Machine].Add(oneTask); } } // ----- Creates model ----- // Creates precedences inside jobs. foreach (List <IntervalVar> jobToTask in jobsToTasks) { int tasksCount = jobToTask.Count; for (int task_index = 0; task_index < tasksCount - 1; ++task_index) { IntervalVar t1 = jobToTask[task_index]; IntervalVar t2 = jobToTask[task_index + 1]; Constraint prec = solver.MakeIntervalVarRelation(t2, Solver.STARTS_AFTER_END, t1); solver.Add(prec); } } // Adds disjunctive constraints on unary resources, and creates // sequence variables. A sequence variable is a dedicated variable // whose job is to sequence interval variables. SequenceVar[] allSequences = new SequenceVar[machinesCount]; for (int machineId = 0; machineId < machinesCount; ++machineId) { string name = "Machine_" + machineId; DisjunctiveConstraint ct = solver.MakeDisjunctiveConstraint(machinesToTasks[machineId].ToArray(), name); solver.Add(ct); allSequences[machineId] = ct.SequenceVar(); } // Creates array of end_times of jobs. IntVar[] allEnds = new IntVar[jobsCount]; for (int i = 0; i < jobsCount; i++) { IntervalVar task = jobsToTasks[i].Last(); allEnds[i] = task.EndExpr().Var(); } // Objective: minimize the makespan (maximum end times of all tasks) // of the problem. IntVar objectiveVar = solver.MakeMax(allEnds).Var(); OptimizeVar objectiveMonitor = solver.MakeMinimize(objectiveVar, 1); // ----- Search monitors and decision builder ----- // This decision builder will rank all tasks on all machines. DecisionBuilder sequencePhase = solver.MakePhase(allSequences, Solver.SEQUENCE_DEFAULT); // After the ranking of tasks, the schedule is still loose and any // task can be postponed at will. But, because the problem is now a PERT // (http://en.wikipedia.org/wiki/Program_Evaluation_and_Review_Technique), // we can schedule each task at its earliest start time. This iscs // conveniently done by fixing the objective variable to its // minimum value. DecisionBuilder objPhase = solver.MakePhase( objectiveVar, Solver.CHOOSE_FIRST_UNBOUND, Solver.ASSIGN_MIN_VALUE); // The main decision builder (ranks all tasks, then fixes the // objectiveVariable). DecisionBuilder mainPhase = solver.Compose(sequencePhase, objPhase); // Search log. const int kLogFrequency = 1000000; SearchMonitor searchLog = solver.MakeSearchLog(kLogFrequency, objectiveMonitor); SearchLimit limit = null; if (timeLimitInMs > 0) { limit = solver.MakeTimeLimit(timeLimitInMs); } SolutionCollector collector = solver.MakeLastSolutionCollector(); collector.Add(allSequences); collector.Add(allTasks.ToArray()); // Search. bool solutionFound = solver.Solve(mainPhase, searchLog, objectiveMonitor, limit, collector); if (solutionFound) { //The index of the solution from the collector const int SOLUTION_INDEX = 0; Assignment solution = collector.Solution(SOLUTION_INDEX); for (int m = 0; m < machinesCount; ++m) { Console.WriteLine("Machine " + m + " :"); SequenceVar seq = allSequences[m]; int[] storedSequence = collector.ForwardSequence(SOLUTION_INDEX, seq); foreach (int taskIndex in storedSequence) { IntervalVar task = seq.Interval(taskIndex); long startMin = solution.StartMin(task); long startMax = solution.StartMax(task); if (startMin == startMax) { Console.WriteLine("Task " + task.Name() + " starts at " + startMin + "."); } else { Console.WriteLine("Task " + task.Name() + " starts between " + startMin + " and " + startMax + "."); } } } } else { Console.WriteLine("No solution found!"); } }
public EntityHistory[] GetSolvedTasks(LotInfoJSON[] data, string startDate, int addMinutes) { List <string> diffList = new List <string>() { "LPN01", "LPN02", "LPN04", "LPP02", "LPP05", "FHT01", "LPT01", "FOX01", "FOX04", "FAL01" }; Funcs funcs = new Funcs(); var date = funcs.StrToDate(startDate); //если передано addMinutes == 25 часов то имеется в виду текущее время if (addMinutes == 25 * 60) { addMinutes = 0; date = DateTime.Now; } //Горизонт событий int horizon = 48 * 60 * 100000; // Creates the model. CpModel model = new CpModel(); // Creates jobs. List <Task> all_tasks = new List <Task>(); //Формирование задач для Солвера foreach (string ent in diffList) { //Задачи одной установки List <LotTask> entityTasks = new List <LotTask>(); foreach (var lot in data) { foreach (var task in lot.Tasks) { if (task.Entity == ent) { entityTasks.Add(task); } } } //Удаляем повторения задач entityTasks = entityTasks.Distinct(new DistinctItemComparer()).ToList(); // Добавляем/дополняем задачи для Солвера foreach (LotTask t in entityTasks) { IntVar start_var = model.NewIntVar(t.Delay, horizon, "Task Start"); int duration = t.Duration; IntVar end_var = model.NewIntVar(0, horizon, "Task End"); IntervalVar interval_var = model.NewIntervalVar( start_var, duration, end_var, String.Join(' ', getLotsFromPaket(data, t.paket))); //String.Format(getLotsFromPaket(data, t.paket) + t.Operation.ToString() + " " + t.Recipe + " " + t.Duration.ToString() + " " + t.Delay)); all_tasks.Add(new Task(start_var, end_var, interval_var, t.Operation, getLotsFromPaket(data, t.paket), t.Entity, t.Recipe, t.paket, getPriority(data, t.Lot), getMaxOperAgo(data, t.Lot), t.Duration)); } } #region Constraints (ограничения, МВХ и условия) /* * // Последовательность запуска задач (согласно № операции) для одной партии * // НЕ ВСЕГДА ВЕРНО!!! * foreach(var lot in data.Select(x => x.Lot).ToList()) * { * var tasks = all_tasks.Where(t => t.lots[0] == lot).ToList().OrderBy(t => t.operation).ToList(); * * for (int t = 1; t < tasks.Count; t++) * model.Add(tasks[t].start >= tasks[t - 1].end); * * }*/ //Назначение приоритетов сортировки по OperAgo & priority foreach (var ent in diffList) { var allEntTasks = all_tasks.Where(e => e.entity == ent).ToList(); if (allEntTasks.Count > 1) { foreach (Task task in allEntTasks) { task.sortPriority = -task.maxOperAgo * 2 + task.priority * 3; // формула расчёта баллов приоритета } allEntTasks = allEntTasks.OrderByDescending(x => x.sortPriority).ToList(); // чем больше приоритет тем раньше старт for (var t0 = 0; t0 < allEntTasks.Count - 1; t0++) { model.Add(allEntTasks[t0].start < allEntTasks[t0 + 1].start); } } } //МВХ захардкожено foreach (var lot in data.Select(x => x.Lot).ToList()) { var tasks = all_tasks.Where(t => t.lots[0] == lot).ToList().OrderBy(t => t.operation).ToList(); var mbx = 14; for (int t = 1; t < tasks.Count; t++) { if (tasks[t].operation == 1015) { mbx = 14; } if (tasks[t].operation == 1120) { mbx = 14; } if (tasks[t].operation == 1350) { mbx = 24; } if (tasks[t].operation == 1380) { mbx = 24; } if (tasks[t].operation == 1390) { mbx = 24; } if (tasks[t].operation == 2280) { mbx = 24; } if (tasks[t].operation == 2292) { mbx = 14; } if (tasks[t].operation == 2390) { mbx = 14; } if (tasks[t].operation == 2410) { mbx = 8; } if (tasks[t].operation == 3270) { mbx = 14; } if (tasks[t].operation == 3280) { mbx = 24; } if (tasks[t].operation == 3390) { mbx = 14; } if (tasks[t].operation == 3410) { mbx = 24; } if (tasks[t].operation == 4520) { mbx = 24; } if (tasks[t].operation == 4560) { mbx = 72; } if (tasks[t].operation == 4960) { mbx = 24; } if (tasks[t].operation == 4990) { mbx = 72; } model.Add(tasks[t].start - tasks[t - 1].end <= mbx); // МВХ 14 часов } } //Ограничение на продувки для FOX01 //Продувки после процесса: После каждого процесса OXIDE16T, OXIDE58TM, OXIDE581TM, OX533TM, // OX531TM, OXIDE70TM, OXPO01C (АЛЬТЕРНАТИВНЫЙ) продувка WET-DCE-CLN - 280 мин var FOX01Tasks = all_tasks.Where(t => t.entity == "FOX01").ToList(); List <string> FOX01Recipies = new List <string>() { "OXIDE16T", "OXIDE58TM", "OXIDE581TM", "OX533TM", "OX531TM", "OXIDE70TM", "OXPO01C" }; for (int t = 0; t < FOX01Tasks.Count; t++) { if (FOX01Recipies.Contains(FOX01Tasks[t].recipe)) { IntVar start_var = model.NewIntVar(0, horizon, "Purge Start"); int duration = 280; IntVar end_var = model.NewIntVar(0, horizon, "Purge End"); IntervalVar interval_var = model.NewIntervalVar(start_var, duration, end_var, "After " + FOX01Tasks[t].recipe + " WET-DCE-CLN 280 min"); var purgeTask = new Task(start_var, end_var, interval_var, 0, new List <string>() { "FOX01 Purge" }, "FOX01", "WET-DCE-CLN", 0, -1, 0, 280); all_tasks.Add(purgeTask); //model.Add(purgeTask.start >= FOX01Tasks[t].end); model.Add(purgeTask.start - FOX01Tasks[t].end < 10); model.Add(purgeTask.start - FOX01Tasks[t].end > 0); } ; } //Ограничение на продувки для LPN02 // До и после обработки NIT1100A, NIT1500A, NITR1500K, NITR01 должна проходить // ОБЯЗАТЕЛЬНО необходимая технологическая продувка 20-CYCLE-PURGE = 200 мин var LPN02Tasks = all_tasks.Where(t => t.entity == "LPN02").ToList(); List <string> LPN02Recipies = new List <string>() { "NIT1100A", "NIT1500A", "NITR1500K", "NITR01" }; //ограничение на продувку после рецепта for (int t = 0; t < LPN02Tasks.Count; t++) { if (LPN02Recipies.Contains(LPN02Tasks[t].recipe)) { IntVar start_var = model.NewIntVar(0, horizon, "Purge Start"); IntVar end_var = model.NewIntVar(0, horizon, "Purge End"); IntervalVar interval_var = model.NewIntervalVar(start_var, 200, end_var, "After " + LPN02Tasks[t].recipe + " 20-CYCLE-PURGE 200 min"); var purgeTaskAfter = new Task(start_var, end_var, interval_var, 0, new List <string> { "Purge After" }, "LPN02", "20-CYCLE-PURGE", 0, -1, 0, 200); all_tasks.Add(purgeTaskAfter); model.Add(purgeTaskAfter.start - LPN02Tasks[t].end < 10); model.Add(purgeTaskAfter.start - LPN02Tasks[t].end > 0); } ; } //ограничение на продувку до рецепта for (int t = 0; t < LPN02Tasks.Count; t++) { if (LPN02Recipies.Contains(LPN02Tasks[t].recipe)) { IntVar start_var = model.NewIntVar(0, horizon, "Purge Start"); IntVar end_var = model.NewIntVar(0, horizon, "Purge End"); IntervalVar interval_var = model.NewIntervalVar(start_var, 200, end_var, "Before " + LPN02Tasks[t].recipe + " 20-CYCLE-PURGE 200 min"); var purgeTaskBefore = new Task(start_var, end_var, interval_var, 0, new List <string> { "Purge Before" }, "LPN02", "20-CYCLE-PURGE", 0, -1, 0, 200); all_tasks.Add(purgeTaskBefore); model.Add(LPN02Tasks[t].start - purgeTaskBefore.end < 10); model.Add(LPN02Tasks[t].start - purgeTaskBefore.end > 0); } ; } //!!!НУЖНО СДЕЛАТЬ!!! Ограничение: запрет 2-х продувок подряд !!!НУЖНО СДЕЛАТЬ!!! //var tasksBefore = all_tasks.Where(b => b.lot == "Purge Before").ToList(); //var tasksAfter = all_tasks.Where(a => a.lot == "Purge After").ToList(); // Ограничение на отсутствие пересечений задач для одной установки foreach (var ent in diffList) { List <IntervalVar> machine_to_jobs = new List <IntervalVar>(); var entTasks = all_tasks.Where(t => (t.entity == ent)).ToList(); for (int j = 0; j < entTasks.Count; j++) { machine_to_jobs.Add(entTasks[j].interval); } model.AddNoOverlap(machine_to_jobs); } var test = all_tasks.Where(t => t.recipe == "MSHTO05").ToList(); // Makespan objective. IntVar[] all_ends = new IntVar[all_tasks.Count]; for (int j = 0; j < all_tasks.Count; j++) { all_ends[j] = all_tasks[j].end; } IntVar makespan = model.NewIntVar(0, horizon, "makespan"); model.AddMaxEquality(makespan, all_ends); model.Minimize(makespan); #endregion // Creates the solver and solve. CpSolver solver = new CpSolver(); //максимальное время расчёта solver.StringParameters = "max_time_in_seconds:" + "40"; solver.Solve(model); #region Преобразование в EntityHistory[] для Gantt chart List <EntityHistory> solvedEntityHistories = new List <EntityHistory>(); DateTime firstDate = new DateTime(1970, 1, 1, 0, 0, 0); long startTime = (long)(date.AddMinutes(addMinutes) - firstDate).TotalSeconds; int id = 0; foreach (var ent in diffList) { var tempEntityHistory = new EntityHistory(); tempEntityHistory.Id = id; tempEntityHistory.Parent = ent; tempEntityHistory.Name = ent + "_план"; var entAllTasks = all_tasks.Where(t => t.entity == ent).ToList(); foreach (Task task in entAllTasks) { LotInfoPeriodGantt per = new LotInfoPeriodGantt(); per.color = getColor(task.priority); per.start = (startTime + solver.Value(task.start) * 60) * 1000 + 120000; per.end = (startTime + solver.Value(task.end) * 60) * 1000 - 120000; per.duration = task.duration; per.id = id; per.lot = task.interval.Name(); per.operation = task.operation.ToString(); per.recipe = task.recipe; per.connectTo = ""; per.connectorType = "finish - start"; tempEntityHistory.Periods.Add(per); id++; } solvedEntityHistories.Add(tempEntityHistory); } #endregion return(solvedEntityHistories.ToArray()); }
public static void WiTiCp(List <TaskWiti> tasks) { var model = new CpModel(); //int variablesMaxValue = 0; int timeSum = tasks.Sum(x => x.P); //foreach (var task in tasks) // variablesMaxValue += ((timeSum - task.D) > 0 ? (timeSum - task.D) : 0) * task.W; IntVar[] starts = new IntVar[tasks.Count]; IntVar[] ends = new IntVar[tasks.Count]; IntVar[] punishment = new IntVar[tasks.Count]; IntervalVar[] intervals = new IntervalVar[tasks.Count]; //var witi = model.NewIntVar(0, variablesMaxValue, "witi"); for (int i = 0; i < tasks.Count; i++) { starts[i] = model.NewIntVar(0, timeSum, $"start_task{i}"); } for (int i = 0; i < tasks.Count; i++) { ends[i] = model.NewIntVar(0, timeSum, $"end_task{i}"); intervals[i] = model.NewIntervalVar(starts[i], tasks[i].P, ends[i], $"interval{i}"); } for (int i = 0; i < tasks.Count; i++) { if ((timeSum - tasks[i].D) > 0) { punishment[i] = model.NewIntVar(0, (timeSum - tasks[i].D) * tasks[i].W, $"punish_task{i}"); } else { punishment[i] = model.NewIntVar(0, 0, $"punish_task{i}"); } } model.AddNoOverlap(intervals); /* * foreach (var task in tasks) * { * model.Add(ends[tasks.IndexOf(task)] == starts[tasks.IndexOf(task)] + task.P); * } * foreach (var task in tasks) * { * model.Add(witi >= (ends[tasks.IndexOf(task)] - task.D) * task.W); * }*/ foreach (var task in tasks) { model.Add(punishment[tasks.IndexOf(task)] >= (ends[tasks.IndexOf(task)] - task.D) * task.W); } //foreach (var task in tasks) //{ // model.Add(punishment[tasks.IndexOf(task)] <= ((timeSum - task.D) > 0 ? (timeSum - task.D) : 0) * task.W); //} var witi = punishment.Sum(); model.Minimize(witi); CpSolver solver = new CpSolver(); solver.StringParameters = "max_time_in_seconds:30.0"; CpSolverStatus solverStatus = solver.Solve(model); if (solverStatus != CpSolverStatus.Optimal) { Console.WriteLine("Solver didn’t find optimal solution!"); } Console.WriteLine("Objective value = " + solver.Value(witi)); }
static void Main(string[] args) { InitTaskList(); int taskCount = GetTaskCount(); Solver solver = new Solver("ResourceConstraintScheduling"); IntervalVar[] tasks = new IntervalVar[taskCount]; IntVar[] taskChoosed = new IntVar[taskCount]; IntVar[] makeSpan = new IntVar[GetEndTaskCount()]; int endJobCounter = 0; foreach (Job j in myJobList) { IntVar[] tmp = new IntVar[j.AlternativeTasks.Count]; int i = 0; foreach (Task t in j.AlternativeTasks) { long ti = taskIndexes[t.Name]; taskChoosed[ti] = solver.MakeIntVar(0, 1, t.Name + "_choose"); tmp[i++] = taskChoosed[ti]; tasks[ti] = solver.MakeFixedDurationIntervalVar( 0, 100000, t.Duration, false, t.Name + "_interval"); if (j.Successor == null) { makeSpan[endJobCounter++] = tasks[ti].EndExpr().Var(); } if (!tasksToEquipment.ContainsKey(t.Equipment)) { tasksToEquipment[t.Equipment] = new List <IntervalVar>(); } tasksToEquipment[t.Equipment].Add(tasks[ti]); } solver.Add(IntVarArrayHelper.Sum(tmp) == 1); } List <SequenceVar> all_seq = new List <SequenceVar>(); foreach (KeyValuePair <long, List <IntervalVar> > pair in tasksToEquipment) { DisjunctiveConstraint dc = solver.MakeDisjunctiveConstraint( pair.Value.ToArray(), pair.Key.ToString()); solver.Add(dc); all_seq.Add(dc.SequenceVar()); } IntVar objective_var = solver.MakeMax(makeSpan).Var(); OptimizeVar objective_monitor = solver.MakeMinimize(objective_var, 1); DecisionBuilder sequence_phase = solver.MakePhase(all_seq.ToArray(), Solver.SEQUENCE_DEFAULT); DecisionBuilder objective_phase = solver.MakePhase(objective_var, Solver.CHOOSE_FIRST_UNBOUND, Solver.ASSIGN_MIN_VALUE); DecisionBuilder main_phase = solver.Compose(sequence_phase, objective_phase); const int kLogFrequency = 1000000; VoidToString prefix = new Prefix(); SearchMonitor search_log = solver.MakeSearchLog(kLogFrequency, objective_monitor, prefix); SolutionCollector collector = solver.MakeLastSolutionCollector(); collector.Add(all_seq.ToArray()); collector.AddObjective(objective_var); if (solver.Solve(main_phase, search_log, objective_monitor, null, collector)) { Console.Out.WriteLine("Optimal solution = " + collector.ObjectiveValue(0)); } else { Console.Out.WriteLine("No solution."); } }
public IntervalVar[] MakeFixedDurationIntervalVarArray(int count, long start_min, long start_max, long duration, bool optional) { IntervalVar[] array = new IntervalVar[count]; for (int i = 0; i < count; ++i) { array[i] = MakeFixedDurationIntervalVar(start_min, start_max, duration, optional, ""); } return array; }
static void Main(string[] args) { InitTaskList(); int taskCount = GetTaskCount(); Solver solver = new Solver("ResourceConstraintScheduling"); IntervalVar[] tasks = new IntervalVar[taskCount]; IntVar[] taskChoosed = new IntVar[taskCount]; IntVar[] makeSpan = new IntVar[GetEndTaskCount()]; int endJobCounter = 0; foreach (Job j in myJobList) { IntVar[] tmp = new IntVar[j.AlternativeTasks.Count]; int i = 0; foreach (Task t in j.AlternativeTasks) { long ti = taskIndexes[t.Name]; taskChoosed[ti] = solver.MakeIntVar(0, 1, t.Name + "_choose"); tmp[i++] = taskChoosed[ti]; tasks[ti] = solver.MakeFixedDurationIntervalVar( 0, 100000, t.Duration, false, t.Name + "_interval"); if (j.Successor == null) makeSpan[endJobCounter++] = tasks[ti].EndExpr().Var(); if (!tasksToEquipment.ContainsKey(t.Equipment)) tasksToEquipment[t.Equipment] = new List<IntervalVar>(); tasksToEquipment[t.Equipment].Add(tasks[ti]); } solver.Add(IntVarArrayHelper.Sum(tmp) == 1); } List<SequenceVar> all_seq = new List<SequenceVar>(); foreach (KeyValuePair<long, List<IntervalVar>> pair in tasksToEquipment) { DisjunctiveConstraint dc = solver.MakeDisjunctiveConstraint( pair.Value.ToArray(), pair.Key.ToString()); solver.Add(dc); all_seq.Add(dc.SequenceVar()); } IntVar objective_var = solver.MakeMax(makeSpan).Var(); OptimizeVar objective_monitor = solver.MakeMinimize(objective_var, 1); DecisionBuilder sequence_phase = solver.MakePhase(all_seq.ToArray(), Solver.SEQUENCE_DEFAULT); DecisionBuilder objective_phase = solver.MakePhase(objective_var, Solver.CHOOSE_FIRST_UNBOUND, Solver.ASSIGN_MIN_VALUE); DecisionBuilder main_phase = solver.Compose(sequence_phase, objective_phase); const int kLogFrequency = 1000000; SearchMonitor search_log = solver.MakeSearchLog(kLogFrequency, objective_monitor); SolutionCollector collector = solver.MakeLastSolutionCollector(); collector.Add(all_seq.ToArray()); collector.AddObjective(objective_var); if (solver.Solve(main_phase, search_log, objective_monitor, null, collector)) Console.Out.WriteLine("Optimal solution = " + collector.ObjectiveValue(0)); else Console.Out.WriteLine("No solution."); }
public static void Solve(FlexibleJobShopData data, bool chatty = false) { // Compute horizon var horizon = data.JobList.Sum( j => j.TaskList.Sum( t => t.Durations.Max())); // ----- Create all intervals and vars ----- /* * // Use some profiling and change the default parameters of the solver * SolverParameters solverParams = new SolverParameters(); * // Change the profile level * solverParams.profile_level = SolverParameters.NORMAL_PROFILING; * // Constraint programming engine * Solver solver = new Solver("JobShop", solverParams); */ // Constraint programming engine Solver solver = new Solver($"FlexibleJobShop: {data.Name}"); // Initialize dictionaries to hold references to task intervals var tasksByJobId = new Dictionary <uint, List <TaskAlternative> >(); foreach (var job in data.JobList) { tasksByJobId[job.Id] = new List <TaskAlternative>(job.TaskList.Count); } var tasksByMachineId = new Dictionary <uint, IntervalVarVector>(); foreach (var machine in data.MachineList) { tasksByMachineId[machine.Id] = new IntervalVarVector(); } // Creates all individual interval variables and collect in dictionaries foreach (var job in data.JobList) { foreach (var task in job.TaskList) { var alternative = new TaskAlternative(job.Id); tasksByJobId[job.Id].Add(alternative); var activeVariables = new IntVarVector(); var hasAlternatives = task.AlternativesCount > 1; for (int alt = 0; alt < task.AlternativesCount; alt++) { var machine = task.Machines[alt]; var duration = task.Durations[alt]; var name = $"{task.Name}; Alternative {alt}: {machine.Name}, Duration {duration}"; IntervalVar interval = solver.MakeFixedDurationIntervalVar(0, horizon, duration, hasAlternatives, name); alternative.Add(interval); tasksByMachineId[machine.Id].Add(interval); if (hasAlternatives) { activeVariables.Add(interval.PerformedExpr().Var()); } } alternative.AlternativeVar = solver.MakeIntVar(0, task.AlternativesCount - 1, task.Name); if (hasAlternatives) { solver.Add(solver.MakeMapDomain(alternative.AlternativeVar, activeVariables)); } } } // ----- Create model ----- // Create precedences inside jobs foreach (var taskAltList in tasksByJobId.Values) { for (int i = 0; i < taskAltList.Count - 1; i++) { TaskAlternative currentTaskAlt = taskAltList[i]; TaskAlternative nextTaskAlt = taskAltList[i + 1]; foreach (var alt1 in currentTaskAlt) { foreach (var alt2 in nextTaskAlt) { solver.Add(solver.MakeIntervalVarRelation( alt2, Solver.STARTS_AFTER_END, alt1)); } } } } // Collect alternative variables. IntVarVector alternativeVariableVec = new IntVarVector(); foreach (var taskAltList in tasksByJobId.Values) { foreach (var taskAlt in taskAltList) { if (!taskAlt.AlternativeVar.Bound()) { alternativeVariableVec.Add(taskAlt.AlternativeVar); } } } // Add disjunctive constraints on unary resources, and create // sequence variables. A sequence variable is a dedicated variable // whose job is to sequence interval variables. SequenceVarVector allSequences = new SequenceVarVector(); foreach (var machine in data.MachineList) { DisjunctiveConstraint disjCt = solver.MakeDisjunctiveConstraint( tasksByMachineId[machine.Id], machine.Name); solver.Add(disjCt); allSequences.Add(disjCt.SequenceVar()); } // Create array of end_times of jobs IntVarVector endsVec = new IntVarVector(); foreach (var taskAltList in tasksByJobId.Values) { TaskAlternative lastTaskAlt = taskAltList.Last(); foreach (var alt in lastTaskAlt) { endsVec.Add(alt.SafeEndExpr(-1).Var()); } } // Objective: minimize the makespan (maximum end times of all tasks) // of the problem. IntVar objectiveVar = solver.MakeMax(endsVec).Var(); OptimizeVar objectiveMonitor = solver.MakeMinimize(objectiveVar, 1); // ----- Search monitors and decision builder ----- // This decision builder will assign all alternative variables. DecisionBuilder alternativePhase = solver.MakePhase(alternativeVariableVec, Solver.CHOOSE_MIN_SIZE, Solver.ASSIGN_MIN_VALUE); // This decision builder will rank all tasks on all machines. DecisionBuilder sequencePhase = solver.MakePhase(allSequences, Solver.SEQUENCE_DEFAULT); // After the ranking of tasks, the schedule is still loose and any // task can be postponed at will. But, because the problem is now a PERT // (http://en.wikipedia.org/wiki/Program_Evaluation_and_Review_Technique), // we can schedule each task at its earliest start time. This is // conveniently done by fixing the objective variable to its // minimum value. DecisionBuilder objectivePhase = solver.MakePhase(objectiveVar, Solver.CHOOSE_FIRST_UNBOUND, Solver.ASSIGN_MIN_VALUE); // The main decision builder (ranks all tasks, then fixes the // objective_variable). DecisionBuilder mainPhase = solver.Compose(alternativePhase, sequencePhase, objectivePhase); // Search log const int kLogFrequency = 1000000; SearchMonitor searchLog = solver.MakeSearchLog(kLogFrequency, objectiveMonitor); const long FLAGS_time_limit_in_ms = 1000 * 60 * 20; SearchLimit limit = null; if (FLAGS_time_limit_in_ms > 0) { limit = solver.MakeTimeLimit(FLAGS_time_limit_in_ms); } SolutionCollector collector = solver.MakeLastSolutionCollector(); collector.AddObjective(objectiveVar); collector.Add(alternativeVariableVec); collector.Add(allSequences); foreach (var taskVec in tasksByMachineId.Values) { foreach (var task in taskVec) { collector.Add(task.StartExpr().Var()); } } // ----- Search ----- bool solutionFound = solver.Solve(mainPhase, searchLog, objectiveMonitor, limit, collector); if (solutionFound) { // The index of the solution from the collector const int SOLUTION_INDEX = 0; Assignment solution = collector.Solution(SOLUTION_INDEX); Console.WriteLine(); uint machineIdx = 0; foreach (var seq in allSequences) { machineIdx++; var taskSeq = collector.ForwardSequence(SOLUTION_INDEX, seq); Console.WriteLine($"{seq.Name()}:"); Console.WriteLine(" Tasks: " + string.Join(", ", taskSeq)); //foreach (var taskIndex in storedSequence) //{ // IntervalVar task = sequence.Interval(taskIndex); // long startMin = solution.StartMin(task); // long startMax = solution.StartMax(task); // if (startMin == startMax) // { // Console.WriteLine($"Task {task.Name()} starts at {startMin}."); // } // else // { // Console.WriteLine($"Task {task.Name()} starts between {startMin} and {startMax}."); // } //} Console.WriteLine(); Console.Write(" Starting times:"); foreach (var s in taskSeq) { Console.Write(" " + collector.Value(0, tasksByMachineId[machineIdx][s].StartExpr().Var()).ToString()); } Console.WriteLine(); } //var x = tasksByMachineId[1][0].StartExpr().Var(); //var xValStr = collector.Value(0, x).ToString(); Console.WriteLine("objective function value = " + solution.ObjectiveValue()); //TEMP } // Save profile in file //solver.ExportProfilingOverview("profile.txt"); // Done solver.EndSearch(); }
public Task(IntVar s, IntVar e, IntervalVar i) { start = s; end = e; interval = i; }
public void RunJobShopScheduling(String solverType) { Solver solver = new Solver(solverType); if (solver == null) { Console.WriteLine("JobShop failed to create a solver " + solverType); return; } // All tasks Dictionary <string, IntervalVar> allTasks = new Dictionary <string, IntervalVar>(); // Creates jobs for (int i = 0; i < allJobs.Count; i++) { for (int j = 0; j < machines.ElementAt(i).Count; j++) { IntervalVar oneTask = solver.MakeFixedDurationIntervalVar(0, horizon, processingTimes.ElementAt(i).ElementAt(j), false, "Job_" + i + "_" + j); allTasks.Add("Job_" + i + "_" + j, oneTask); } } // Create sequence variables and add disjuctive constraints List <SequenceVar> allSequences = new List <SequenceVar>(); foreach (var machine in allMachines) { List <IntervalVar> machinesJobs = new List <IntervalVar>(); for (int i = 0; i < allJobs.Count; i++) { for (int k = 0; k < machines.ElementAt(i).Count; k++) { if (machines.ElementAt(i).ElementAt(k) == machine) { machinesJobs.Add(allTasks["Job_" + i + "_" + k]); } } } DisjunctiveConstraint disj = solver.MakeDisjunctiveConstraint(machinesJobs.ToArray(), "machine " + machine); allSequences.Add(disj.SequenceVar()); solver.Add(disj); } // Add conjunctive constraints foreach (var job in allJobs) { for (int j = 0; j < machines.ElementAt(job).Count - 1; j++) { solver.Add(allTasks["Job_" + job + "_" + (j + 1)].StartsAfterEnd(allTasks["Job_" + job + "_" + j])); } } // Set the objective IntVar[] allEnds = new IntVar[jobsCount]; for (int i = 0; i < allJobs.Count; i++) { allEnds[i] = allTasks["Job_" + i + "_" + (machines.ElementAt(i).Count - 1)].EndExpr().Var(); } // Objective: minimize the makespan (maximum end times of all tasks) // of the problem. IntVar objectiveVar = solver.MakeMax(allEnds).Var(); OptimizeVar objectiveMonitor = solver.MakeMinimize(objectiveVar, 1); // Create search phases DecisionBuilder sequencePhase = solver.MakePhase(allSequences.ToArray(), Solver.SEQUENCE_DEFAULT); DecisionBuilder varsPhase = solver.MakePhase(objectiveVar, Solver.CHOOSE_FIRST_UNBOUND, Solver.ASSIGN_MIN_VALUE); // The main decision builder (ranks all tasks, then fixes the // objectiveVariable). DecisionBuilder mainPhase = solver.Compose(sequencePhase, varsPhase); SolutionCollector collector = solver.MakeLastSolutionCollector(); collector.Add(allSequences.ToArray()); collector.Add(objectiveVar); foreach (var i in allMachines) { SequenceVar sequence = allSequences.ElementAt(i); long sequenceCount = sequence.Size(); for (int j = 0; j < sequenceCount; j++) { IntervalVar t = sequence.Interval(j); collector.Add(t.StartExpr().Var()); collector.Add(t.EndExpr().Var()); } } // Search. bool solutionFound = solver.Solve(mainPhase, null, objectiveMonitor, null, collector); if (solutionFound) { //The index of the solution from the collector const int SOLUTION_INDEX = 0; Assignment solution = collector.Solution(SOLUTION_INDEX); string solLine = ""; string solLineTasks = ""; Console.WriteLine("Time Intervals for Tasks\n"); for (int m = 0; m < this.machinesCount; m++) { //Console.WriteLine("MachineCount: " + this.machinesCount); solLine = "Machine " + m + " :"; solLineTasks = "Machine " + m + ": "; SequenceVar seq = allSequences.ElementAt(m); int[] storedSequence = collector.ForwardSequence(SOLUTION_INDEX, seq); foreach (int taskIndex in storedSequence) { //Console.WriteLine("taskIndex: " + taskIndex); IntervalVar task = seq.Interval(taskIndex); solLineTasks += task.Name() + " "; //Console.WriteLine("Len: " + storedSequence.Length); } foreach (int taskIndex in storedSequence) { IntervalVar task = seq.Interval(taskIndex); string solTemp = "[" + collector.Value(0, task.StartExpr().Var()) + ","; solTemp += collector.Value(0, task.EndExpr().Var()) + "] "; solLine += solTemp; } //solLine += "\n"; solLineTasks += "\n"; //Console.WriteLine(solLineTasks); Console.WriteLine(solLine); } } else { Console.WriteLine("No solution found!"); } }
public static void Main(String[] args) { InitTaskList(); CpModel model = new CpModel(); // ----- Creates all intervals and integer variables ----- // Stores all tasks attached interval variables per job. List <List <IntervalVar> > jobsToTasks = new List <List <IntervalVar> >(jobsCount); List <List <IntVar> > jobsToStarts = new List <List <IntVar> >(jobsCount); List <List <IntVar> > jobsToEnds = new List <List <IntVar> >(jobsCount); // machinesToTasks stores the same interval variables as above, but // grouped my machines instead of grouped by jobs. List <List <IntervalVar> > machinesToTasks = new List <List <IntervalVar> >(machinesCount); List <List <IntVar> > machinesToStarts = new List <List <IntVar> >(machinesCount); for (int i = 0; i < machinesCount; i++) { machinesToTasks.Add(new List <IntervalVar>()); machinesToStarts.Add(new List <IntVar>()); } // Creates all individual interval variables. foreach (List <Task> job in myJobList) { jobsToTasks.Add(new List <IntervalVar>()); jobsToStarts.Add(new List <IntVar>()); jobsToEnds.Add(new List <IntVar>()); foreach (Task task in job) { IntVar start = model.NewIntVar(0, horizon, task.Name); IntVar end = model.NewIntVar(0, horizon, task.Name); IntervalVar oneTask = model.NewIntervalVar(start, task.Duration, end, task.Name); jobsToTasks[task.JobId].Add(oneTask); jobsToStarts[task.JobId].Add(start); jobsToEnds[task.JobId].Add(end); machinesToTasks[task.Machine].Add(oneTask); machinesToStarts[task.Machine].Add(start); } } // ----- Creates model ----- // Creates precedences inside jobs. for (int j = 0; j < jobsToTasks.Count; ++j) { for (int t = 0; t < jobsToTasks[j].Count - 1; ++t) { model.Add(jobsToEnds[j][t] <= jobsToStarts[j][t + 1]); } } // Adds no_overkap constraints on unary resources. for (int machineId = 0; machineId < machinesCount; ++machineId) { model.AddNoOverlap(machinesToTasks[machineId]); } // Creates array of end_times of jobs. IntVar[] allEnds = new IntVar[jobsCount]; for (int i = 0; i < jobsCount; i++) { allEnds[i] = jobsToEnds[i].Last(); } // Objective: minimize the makespan (maximum end times of all tasks) // of the problem. IntVar makespan = model.NewIntVar(0, horizon, "makespan"); model.AddMaxEquality(makespan, allEnds); model.Minimize(makespan); // Create the solver. CpSolver solver = new CpSolver(); // Set the time limit. if (timeLimitInSeconds > 0) { solver.StringParameters = "max_time_in_seconds:" + timeLimitInSeconds; } // Solve the problem. CpSolverStatus status = solver.Solve(model); if (status == CpSolverStatus.Optimal) { Console.WriteLine("Makespan = " + solver.ObjectiveValue); for (int m = 0; m < machinesCount; ++m) { Console.WriteLine($"Machine {m}:"); SortedDictionary <long, string> starts = new SortedDictionary <long, string>(); foreach (IntVar var in machinesToStarts[m]) { starts[solver.Value(var)] = var.Name(); } foreach (KeyValuePair <long, string> p in starts) { Console.WriteLine($" Task {p.Value} starts at {p.Key}"); } } } else { Console.WriteLine("No solution found!"); } }
public IntervalVar[] MakeFixedDurationIntervalVarArray(IntVar[] starts, long[] durations, string name) { int count = starts.Length; IntervalVar[] array = new IntervalVar[count]; for (int i = 0; i < count; ++i) { array[i] = MakeFixedDurationIntervalVar(starts[i], durations[i], name + i); } return array; }
/** * * Moving furnitures (scheduling) problem in Google CP Solver. * * Marriott & Stukey: 'Programming with constraints', page 112f * * Also see http://www.hakank.org/or-tools/furniture_moving.py * */ private static void Solve() { Solver solver = new Solver("FurnitureMovingIntervals"); const int n = 4; int[] durations = { 30, 10, 15, 15 }; int[] demand = { 3, 1, 3, 2 }; const int upper_limit = 160; const int max_num_workers = 5; // // Decision variables // IntervalVar[] tasks = new IntervalVar[n]; for (int i = 0; i < n; ++i) { tasks[i] = solver.MakeFixedDurationIntervalVar(0, upper_limit - durations[i], durations[i], false, "task_" + i); } // Fillers that span the whole resource and limit the available // number of workers. IntervalVar[] fillers = new IntervalVar[max_num_workers]; for (int i = 0; i < max_num_workers; ++i) { fillers[i] = solver.MakeFixedDurationIntervalVar(0, 0, upper_limit, true, "filler_" + i); } // Number of needed resources, to be minimized or constrained. IntVar num_workers = solver.MakeIntVar(0, max_num_workers, "num_workers"); // Links fillers and num_workers. for (int i = 0; i < max_num_workers; ++i) { solver.Add((num_workers > i) + fillers[i].PerformedExpr() == 1); } // Creates makespan. IntVar[] ends = new IntVar[n]; for (int i = 0; i < n; ++i) { ends[i] = tasks[i].EndExpr().Var(); } IntVar end_time = ends.Max().VarWithName("end_time"); // // Constraints // IntervalVar[] all_tasks = new IntervalVar[n + max_num_workers]; int[] all_demands = new int[n + max_num_workers]; for (int i = 0; i < n; ++i) { all_tasks[i] = tasks[i]; all_demands[i] = demand[i]; } for (int i = 0; i < max_num_workers; ++i) { all_tasks[i + n] = fillers[i]; all_demands[i + n] = 1; } solver.Add(all_tasks.Cumulative(all_demands, max_num_workers, "workers")); // // Some extra constraints to play with // // all tasks must end within an hour // solver.Add(end_time <= 60); // All tasks should start at time 0 // for(int i = 0; i < n; i++) { // solver.Add(tasks[i].StartAt(0)); // } // limitation of the number of people // solver.Add(num_workers <= 3); solver.Add(num_workers <= 4); // // Objective // // OptimizeVar obj = num_workers.Minimize(1); OptimizeVar obj = end_time.Minimize(1); // // Search // DecisionBuilder db = solver.MakePhase(all_tasks, Solver.INTERVAL_DEFAULT); solver.NewSearch(db, obj); while (solver.NextSolution()) { Console.WriteLine(num_workers.ToString() + ", " + end_time.ToString()); for (int i = 0; i < n; i++) { Console.WriteLine("{0} (demand:{1})", tasks[i].ToString(), demand[i]); } Console.WriteLine(); } Console.WriteLine("Solutions: {0}", solver.Solutions()); Console.WriteLine("WallTime: {0} ms", solver.WallTime()); Console.WriteLine("Failures: {0}", solver.Failures()); Console.WriteLine("Branches: {0} ", solver.Branches()); solver.EndSearch(); }
/** * * Moving furnitures (scheduling) problem in Google CP Solver. * * Marriott & Stukey: 'Programming with constraints', page 112f * * Also see http://www.hakank.org/or-tools/furniture_moving.py * */ private static void Solve() { Solver solver = new Solver("FurnitureMovingIntervals"); const int n = 4; int[] durations = {30,10,15,15}; int[] demand = {3, 1, 3, 2}; const int upper_limit = 160; const int max_num_workers = 5; // // Decision variables // IntervalVar[] tasks = new IntervalVar[n]; for (int i = 0; i < n; ++i) { tasks[i] = solver.MakeFixedDurationIntervalVar(0, upper_limit - durations[i], durations[i], false, "task_" + i); } // Fillers that span the whole resource and limit the available // number of workers. IntervalVar[] fillers = new IntervalVar[max_num_workers]; for (int i = 0; i < max_num_workers; ++i) { fillers[i] = solver.MakeFixedDurationIntervalVar(0, 0, upper_limit, true, "filler_" + i); } // Number of needed resources, to be minimized or constrained. IntVar num_workers = solver.MakeIntVar(0, max_num_workers, "num_workers"); // Links fillers and num_workers. for (int i = 0; i < max_num_workers; ++i) { solver.Add((num_workers > i) + fillers[i].PerformedExpr() == 1); } // Creates makespan. IntVar[] ends = new IntVar[n]; for (int i = 0; i < n; ++i) { ends[i] = tasks[i].EndExpr().Var(); } IntVar end_time = ends.Max().VarWithName("end_time"); // // Constraints // IntervalVar[] all_tasks = new IntervalVar[n + max_num_workers]; int[] all_demands = new int[n + max_num_workers]; for (int i = 0; i < n; ++i) { all_tasks[i] = tasks[i]; all_demands[i] = demand[i]; } for (int i = 0; i < max_num_workers; ++i) { all_tasks[i + n] = fillers[i]; all_demands[i + n] = 1; } solver.Add(all_tasks.Cumulative(all_demands, max_num_workers, "workers")); // // Some extra constraints to play with // // all tasks must end within an hour // solver.Add(end_time <= 60); // All tasks should start at time 0 // for(int i = 0; i < n; i++) { // solver.Add(tasks[i].StartAt(0)); // } // limitation of the number of people // solver.Add(num_workers <= 3); solver.Add(num_workers <= 4); // // Objective // // OptimizeVar obj = num_workers.Minimize(1); OptimizeVar obj = end_time.Minimize(1); // // Search // DecisionBuilder db = solver.MakePhase(all_tasks, Solver.INTERVAL_DEFAULT); solver.NewSearch(db, obj); while (solver.NextSolution()) { Console.WriteLine(num_workers.ToString() + ", " + end_time.ToString()); for(int i = 0; i < n; i++) { Console.WriteLine("{0} (demand:{1})", tasks[i].ToString(), demand[i]); } Console.WriteLine(); } Console.WriteLine("Solutions: {0}", solver.Solutions()); Console.WriteLine("WallTime: {0} ms", solver.WallTime()); Console.WriteLine("Failures: {0}", solver.Failures()); Console.WriteLine("Branches: {0} ", solver.Branches()); solver.EndSearch(); }