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 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(); }