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 void PostTransitionTimeConstraints(int t, bool postTransitionsConstraint = true) { Tool tool = factoryData.Tools[t]; // if it is a inspection, we make sure there are no transitiontimes if (tool.CanPerformTaskType(factoryData.Inspection)) { tool2TransitionTimes[t].Add(null); } else { int[,] tt = tool.TravellingTime; SequenceVar seq = allToolSequences[t]; long s = seq.Size(); IntVar[] nextLocation = new IntVar[s + 1]; // The seq.Next(i) represents the task performed after the i-th // task in the sequence seq.Next(0) represents the first task // performed for extracting travelling times we need to get the // related location In case a task is not performed (seq.Next(i) // == i), i.e. it's pointing to itself The last performed task // (or pre-start task, if no tasks are performed) will have // seq.Next(i) == s + 1 therefore we add a virtual location // whose travelling time is equal to 0 // // NOTE: The index of a SequenceVar are 0..n, but the domain // range is 1..(n+1), this is due to that the start node = 0 is // a dummy node, and the node where seq.Next(i) == n+1 is the // end node // Extra elements for the unreachable start node (0), and the // end node whose next task takes place in a virtual location int[] taskIndex2locationId = new int[s + 2]; taskIndex2locationId[0] = -10; for (int i = 0; i < s; i++) { taskIndex2locationId[i + 1] = tasks[toolIntervalVar2TaskId[t][i]].LocationId; } // this is the virtual location for unperformed tasks taskIndex2locationId[s + 1] = factoryData.NbWorkLocations; // Build the travelling time matrix with the additional virtual location int[][] ttWithVirtualLocation = new int [factoryData.NbWorkLocations + 1][]; for (int d1 = 0; d1 < ttWithVirtualLocation.Length; d1++) { ttWithVirtualLocation[d1] = new int[factoryData.NbWorkLocations + 1]; for (int d2 = 0; d2 < ttWithVirtualLocation.Length; d2++) { if (d1 == factoryData.NbWorkLocations) { ttWithVirtualLocation[d1][d2] = 0; } else { ttWithVirtualLocation[d1][d2] = (d2 == factoryData.NbWorkLocations) ? 0 : tt[d1, d2]; } } } for (int i = 0; i < nextLocation.Length; i++) { // this is the next-location associated with the i-th task nextLocation[i] = solver.MakeElement(taskIndex2locationId, seq.Next(i)).Var(); int d = (i == 0) ? tool.InitialLocationId : tasks[toolIntervalVar2TaskId[t][i - 1]].LocationId; if (i == 0) { // To be changed - right now we don't have meaningful indata // of previous location Ugly way of setting initial travel // time to = 0, as this is how we find common grounds // between benchmark algorithm and this tool2TransitionTimes[t].Add( solver.MakeElement(new int[ttWithVirtualLocation[d].Length], nextLocation[i]) .Var()); } else { tool2TransitionTimes[t].Add( solver.MakeElement(ttWithVirtualLocation[d], nextLocation[i]).Var()); } } // Extra elements for the unreachable start node (0), and the // end node whose next task takes place in a virtual location startingTimes[t] = new IntVar[s + 2]; endTimes[t] = new IntVar[s + 2]; startingTimes[t][0] = solver.MakeIntConst(0); // Tbd: Set this endtime to the estimated time of finishing // previous task for the current tool endTimes[t][0] = solver.MakeIntConst(0); for (int i = 0; i < s; i++) { startingTimes[t][i + 1] = tool2Task[t][i].SafeStartExpr(-1).Var(); endTimes[t][i + 1] = tool2Task[t][i].SafeEndExpr(-1).Var(); } startingTimes[t][s + 1] = solver.MakeIntConst(factoryData.Horizon); endTimes[t][s + 1] = solver.MakeIntConst(factoryData.Horizon); // Enforce (or not) that each task is separated by the // transition time to the next task for (int i = 0; i < nextLocation.Length; i++) { IntVar nextStart = solver.MakeElement(startingTimes[t], seq.Next(i).Var()).Var(); if (postTransitionsConstraint) { solver.Add(endTimes[t][i] + tool2TransitionTimes[t][i] <= nextStart); } } } }
/** * * * 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(); }
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!"); } }
/** * * * Organizing a day. * * Simple scheduling problem. * * Problem formulation from ECLiPSe: * Slides on (Finite Domain) Constraint Logic Programming, page 38f * http://eclipse-clp.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(); }
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!"); } }