private void ExtractSingletonLabelsFrom(SolutionCollector theSolutionCollector) { foreach (var variableTuple in this.orToolsCache.SingletonVariableMap) { var solverValue = theSolutionCollector.Value(0, variableTuple.Value.Item2); var modelValue = ConvertSolverValueToModel(variableTuple.Value.Item1, solverValue); var newValue = new SingletonVariableLabelModel(variableTuple.Value.Item1, new ValueModel(modelValue)); this.snapshot.AddSingletonLabel(newValue); } }
private void ExtractAggregateLabelsFrom(SolutionCollector theSolutionCollector) { foreach (var aggregateTuple in this.orToolsCache.AggregateVariableMap) { var newValueBindings = new List <ValueModel>(); var orVariables = aggregateTuple.Value.Item2; foreach (var orVariable in orVariables) { var solverValue = theSolutionCollector.Value(0, orVariable); var modelValue = ConvertSolverValueToModel(aggregateTuple.Value.Item1, solverValue); newValueBindings.Add(new ValueModel(modelValue)); } var newCompoundLabel = new AggregateVariableLabelModel(aggregateTuple.Value.Item1, newValueBindings); this.snapshot.AddAggregateLabel(newCompoundLabel); } }
private void ExtractBucketLabelFrom(SolutionCollector solutionCollector, OrBucketVariableMap bucketVariableMap) { var bundleLabels = new List <BundleLabelModel>(); foreach (var bundleMap in bucketVariableMap.GetBundleMaps()) { var variableLabels = new List <SingletonVariableLabelModel>(); foreach (var variableMap in bundleMap.GetVariableMaps()) { var solverValue = solutionCollector.Value(0, variableMap.SolverVariable); var modelValue = ConvertSolverValueToModel(bucketVariableMap.Bucket, solverValue); variableLabels.Add(new SingletonVariableLabelModel(variableMap.ModelVariable, new ValueModel(modelValue))); } bundleLabels.Add(new BundleLabelModel(bucketVariableMap.Bucket.Bundle, variableLabels)); } var bucketLabel = new BucketLabelModel(bucketVariableMap.Bucket, bundleLabels); this.snapshot.AddBucketLabel(bucketLabel); }
// We don't need helper functions here // Csharp syntax is easier than C++ syntax! private static void CPisFun(int kBase, int time_limit_param, bool print) { // Use some profiling and change the default parameters of the solver SolverParameters solver_params = new SolverParameters(); // Change the profile level solver_params.profile_level = SolverParameters.NORMAL_PROFILING; // Constraint Programming engine Solver solver = new Solver("CP is fun!", solver_params); // Decision variables IntVar c = solver.MakeIntVar(1, kBase - 1, "C"); IntVar p = solver.MakeIntVar(0, kBase - 1, "P"); IntVar i = solver.MakeIntVar(1, kBase - 1, "I"); IntVar s = solver.MakeIntVar(0, kBase - 1, "S"); IntVar f = solver.MakeIntVar(1, kBase - 1, "F"); IntVar u = solver.MakeIntVar(0, kBase - 1, "U"); IntVar n = solver.MakeIntVar(0, kBase - 1, "N"); IntVar t = solver.MakeIntVar(1, kBase - 1, "T"); IntVar r = solver.MakeIntVar(0, kBase - 1, "R"); IntVar e = solver.MakeIntVar(0, kBase - 1, "E"); // We need to group variables in a vector to be able to use // the global constraint AllDifferent IntVar[] letters = new IntVar[] { c, p, i, s, f, u, n, t, r, e }; // Check if we have enough digits if (kBase < letters.Length) { throw new Exception("kBase < letters.Length"); } // Constraints solver.Add(letters.AllDifferent()); // CP + IS + FUN = TRUE solver.Add(p + s + n + kBase * (c + i + u) + kBase * kBase * f == e + kBase * u + kBase * kBase * r + kBase * kBase * kBase * t); SolutionCollector all_solutions = solver.MakeAllSolutionCollector(); // Add the interesting variables to the SolutionCollector all_solutions.Add(letters); // Decision Builder: hot to scour the search tree DecisionBuilder db = solver.MakePhase(letters, Solver.CHOOSE_FIRST_UNBOUND, Solver.ASSIGN_MIN_VALUE); // Add some time limit SearchLimit time_limit = solver.MakeTimeLimit(time_limit_param); solver.Solve(db, all_solutions, time_limit); // Retrieve the solutions int numberSolutions = all_solutions.SolutionCount(); Console.WriteLine("Number of solutions: " + numberSolutions); if (print) { for (int index = 0; index < numberSolutions; ++index) { Console.Write("C=" + all_solutions.Value(index, c)); Console.Write(" P=" + all_solutions.Value(index, p)); Console.Write(" I=" + all_solutions.Value(index, i)); Console.Write(" S=" + all_solutions.Value(index, s)); Console.Write(" F=" + all_solutions.Value(index, f)); Console.Write(" U=" + all_solutions.Value(index, u)); Console.Write(" N=" + all_solutions.Value(index, n)); Console.Write(" T=" + all_solutions.Value(index, t)); Console.Write(" R=" + all_solutions.Value(index, r)); Console.Write(" E=" + all_solutions.Value(index, e)); Console.WriteLine(); } } // Save profile in file solver.ExportProfilingOverview("profile.txt"); }
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(); }