/** * * * 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(); }
static void SequenceTest() { Solver solver = new Solver("TestSequence"); 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); Console.WriteLine(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 < duration; ++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(); }