public void Sequence() { Solver solver = new Solver("Solver"); IntervalVar[] intervals = solver.MakeFixedDurationIntervalVarArray(10, 0, 10, 5, false, "task"); DisjunctiveConstraint disjunctive = intervals.Disjunctive("Sequence"); SequenceVar var = disjunctive.SequenceVar(); Assignment ass = solver.MakeAssignment(); ass.Add(var); ass.SetForwardSequence(var, new int[] { 1, 3, 5 }); int[] seq = ass.ForwardSequence(var); Assert.Equal(3, seq.Length); }
private static void Solve(int first_slot) { Console.WriteLine("----------------------------------------------------"); Solver solver = new Solver("SpeakerScheduling"); // the slots each speaker is available int[][] speaker_availability = { new int[] { 1, 3, 4, 6, 7, 10, 12, 13, 14, 15, 16, 18, 19, 20, 21, 22, 23, 24, 25, 33, 34, 35, 36, 37, 38, 39, 40, 41, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 54, 55, 56, 57, 58, 59 }, new int[] { 1, 2, 7, 8, 10, 11, 16, 17, 18, 21, 22, 23, 24, 25, 33, 34, 35, 36, 37, 38, 39, 40, 42, 43, 44, 45, 46, 47, 48, 49, 52, 53, 54, 55, 56, 57, 58, 59,60 }, new int[] { 5, 6, 7, 10, 12, 14, 16, 17, 21, 22, 23, 24, 33, 35, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 51, 53, 55, 56, 57, 58,59 }, new int[] { 1, 2, 3, 4, 5, 6, 7, 11, 13, 14, 15, 16, 20, 24, 25, 33, 34, 35, 37, 38, 39, 40, 41, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, 54, 55, 56, 58, 59,60 }, new int[] { 4, 7, 8, 9, 16, 17, 19, 20, 21, 22, 23, 24, 25, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 49, 50, 51, 53, 55, 56, 57, 58, 59,60 }, new int[] { 4, 7, 9, 11, 12, 13, 14, 15, 16, 17, 18, 22, 23, 24, 33, 34, 35, 36, 38, 39, 42, 44, 46, 48, 49, 51, 53, 54, 55, 56,57 }, new int[] { 1, 2, 3, 4, 5, 6, 7, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 54, 55, 56, 57, 58, 59,60 }, new int[] { 1, 3, 11, 14, 15, 16, 17, 21, 22, 23, 24, 25, 33, 35, 36, 37, 39, 40, 41, 42, 43, 44, 45, 47, 48, 49, 51, 52, 53, 54, 55, 56, 57, 58, 59,60 }, new int[] { 1, 2, 3, 4, 5, 7, 8, 9, 10, 11, 13, 18, 19, 20, 21, 22, 23, 24, 25, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 50, 51, 52, 53, 54, 55, 56, 57, 59,60 }, new int[] { 24, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 45, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59,60 }, new int[] { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 16, 17, 18, 19, 20, 22, 23, 24, 25, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 50, 51, 52, 53,55, 56, 57, 58, 59, 60 }, new int[] { 3, 4, 5, 6, 13, 15, 16, 17, 18, 19, 21, 22, 24, 25, 33, 34, 35, 36, 37, 39, 40, 41, 42, 43, 44, 45, 47, 52, 53, 55, 57, 58, 59,60 }, new int[] { 4, 5, 6, 8, 11, 12, 13, 14, 17, 19, 20, 22, 23, 24, 25, 33, 34, 35, 36, 37, 39, 40, 41, 42, 43, 47, 48, 49, 50, 51, 52, 55, 56,57 }, new int[] { 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,52, 53, 54, 55, 56, 57, 58, 59, 60 }, new int[] { 12, 25, 33, 35, 36, 37, 39, 41, 42, 43, 48, 51, 52, 53, 54, 57, 59,60 }, new int[] { 4, 8, 16, 17, 19, 23, 25, 33, 34, 35, 37, 41, 44, 45, 47, 48, 49,50 }, new int[] { 3, 23, 24, 25, 33, 35, 36, 37, 38, 39, 40, 42, 43, 44, 49, 50, 53, 54, 55, 56, 57, 58,60 }, new int[] { 7, 13, 19, 20, 22, 23, 24, 25, 33, 34, 35, 38, 40, 41, 42, 44, 45, 46, 47, 48, 49, 52, 53, 54, 58, 59, 60 } }; // how long each talk lasts for each speaker int[] durations = { 1, 2, 1, 1, 2, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 1, 1 }; int sum_of_durations = durations.Sum(); int number_of_speakers = durations.Length; // calculate the total number of slots (maximum in the availability array) // (and add the max durations) int last_slot = (from s in Enumerable.Range(0, number_of_speakers) select speaker_availability[s].Max()).Max(); Console.WriteLine( "Scheduling {0} speakers, for a total of {1} slots, during [{2}..{3}]", number_of_speakers, sum_of_durations, first_slot, last_slot); // Start variable for all talks. IntVar[] starts = new IntVar[number_of_speakers]; // We store the possible starts for all talks filtered from the // duration and the speaker availability. int[][] possible_starts = new int[number_of_speakers][]; for (int speaker = 0; speaker < number_of_speakers; ++speaker) { int duration = durations[speaker]; // Let's filter the possible starts. List <int> filtered_starts = new List <int>(); int availability = speaker_availability[speaker].Length; for (int index = 0; index < availability; ++index) { bool ok = true; int slot = speaker_availability[speaker][index]; if (slot < first_slot) { continue; } for (int offset = 1; offset < durations[speaker]; ++offset) { if (index + offset >= availability || speaker_availability[speaker][index + offset] != slot + offset) { // discontinuity. ok = false; break; } } if (ok) { filtered_starts.Add(slot); } possible_starts[speaker] = filtered_starts.ToArray(); } starts[speaker] = solver.MakeIntVar(possible_starts[speaker], "start[" + speaker + "]"); } List <IntVar>[] contributions_per_slot = new List <IntVar> [last_slot + 1]; for (int slot = first_slot; slot <= last_slot; ++slot) { contributions_per_slot[slot] = new List <IntVar>(); } for (int speaker = 0; speaker < number_of_speakers; ++speaker) { int duration = durations[speaker]; IntVar start_var = starts[speaker]; foreach (int start in possible_starts[speaker]) { for (int offset = 0; offset < duration; ++offset) { contributions_per_slot[start + offset].Add(start_var.IsEqual(start)); } } } // Force the schedule to be consistent. for (int slot = first_slot; slot <= last_slot; ++slot) { solver.Add( solver.MakeSumLessOrEqual(contributions_per_slot[slot].ToArray(), 1)); } // Add minimum start info. for (int speaker = 0; speaker < number_of_speakers; ++speaker) { solver.Add(starts[speaker] >= first_slot); } // Creates makespan. IntVar[] end_times = new IntVar[number_of_speakers]; for (int speaker = 0; speaker < number_of_speakers; speaker++) { end_times[speaker] = (starts[speaker] + (durations[speaker] - 1)).Var(); } IntVar last_slot_var = end_times.Max().VarWithName("last_slot"); // Add trivial bound to objective. last_slot_var.SetMin(first_slot + sum_of_durations - 1); // Redundant scheduling constraint. IntervalVar[] intervals = solver.MakeFixedDurationIntervalVarArray(starts, durations, "intervals"); DisjunctiveConstraint disjunctive = solver.MakeDisjunctiveConstraint(intervals, "disjunctive"); solver.Add(disjunctive); // // Search // List <IntVar> short_talks = new List <IntVar>(); List <IntVar> long_talks = new List <IntVar>(); for (int speaker = 0; speaker < number_of_speakers; ++speaker) { if (durations[speaker] == 1) { short_talks.Add(starts[speaker]); } else { long_talks.Add(starts[speaker]); } } OptimizeVar objective_monitor = solver.MakeMinimize(last_slot_var, 1); DecisionBuilder long_phase = solver.MakePhase(long_talks.ToArray(), Solver.CHOOSE_MIN_SIZE_LOWEST_MIN, Solver.ASSIGN_MIN_VALUE); DecisionBuilder short_phase = new FlowAssign(short_talks.ToArray(), first_slot, last_slot_var); DecisionBuilder obj_phase = solver.MakePhase(last_slot_var, Solver.CHOOSE_FIRST_UNBOUND, Solver.ASSIGN_MIN_VALUE); DecisionBuilder main_phase = solver.Compose(long_phase, short_phase, obj_phase); solver.NewSearch(main_phase, objective_monitor); while (solver.NextSolution()) { Console.WriteLine("\nLast used slot: " + (last_slot_var.Value())); Console.WriteLine("Speakers (start..end):"); for (int s = 0; s < number_of_speakers; s++) { long sstart = starts[s].Value(); Console.WriteLine(" - speaker {0,2}: {1,2}..{2,2}", (s + 1), sstart, (sstart + durations[s] - 1)); } } Console.WriteLine("\nSolutions: {0}", solver.Solutions()); Console.WriteLine("WallTime: {0}ms", solver.WallTime()); Console.WriteLine("Failures: {0}", solver.Failures()); Console.WriteLine("Branches: {0} ", solver.Branches()); solver.EndSearch(); }
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); }
/** * * * Organizing a day. * * Simple scheduling problem. * * Problem formulation from ECLiPSe: * Slides on (Finite Domain) Constraint Logic Programming, page 38f * http://eclipseclp.org/reports/eclipse.ppt * * * Also see http://www.hakank.org/google_or_tools/organize_day.py * */ private static void Solve() { Solver solver = new Solver("OrganizeDayIntervals"); int n = 4; int work = 0; int mail = 1; int shop = 2; int bank = 3; // the valid times of the day int begin = 9; int end = 17; // tasks int[] tasks = { work, mail, shop, bank }; // durations int[] durations = { 4, 1, 2, 1 }; // Arrays for interval variables. int[] starts_max = { begin, begin, begin, begin }; int[] ends_max = { end - 4, end - 1, end - 2, end - 1 }; // task [i,0] must be finished before task [i,1] int[,] before_tasks = { { bank, shop }, { mail, work } }; // // Decision variables // IntervalVar[] intervals = solver.MakeFixedDurationIntervalVarArray(n, starts_max, ends_max, durations, false, "task"); // // Constraints // DisjunctiveConstraint disjunctive = intervals.Disjunctive("Sequence"); solver.Add(disjunctive); // specific constraints for (int t = 0; t < before_tasks.GetLength(0); t++) { int before = before_tasks[t, 0]; int after = before_tasks[t, 1]; solver.Add(intervals[after].StartsAfterEnd(intervals[before])); } solver.Add(intervals[work].StartsAfter(11)); // // Search // SequenceVar var = disjunctive.SequenceVar(); SequenceVar[] seq_array = new SequenceVar[] { var }; DecisionBuilder db = solver.MakePhase(seq_array, Solver.SEQUENCE_DEFAULT); solver.NewSearch(db); while (solver.NextSolution()) { foreach (int t in tasks) { Console.WriteLine(intervals[t].ToString()); } Console.WriteLine(); } Console.WriteLine("\nSolutions: {0}", solver.Solutions()); Console.WriteLine("WallTime: {0}ms", solver.WallTime()); Console.WriteLine("Failures: {0}", solver.Failures()); Console.WriteLine("Branches: {0} ", solver.Branches()); solver.EndSearch(); }
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 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 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 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 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!"); } }