def test_resource_tasks_distance_single_time_period_2(self) -> None: """The same as above, except that we force the tasks to be scheduled in the time period so that the distance applies""" pb = ps.SchedulingProblem("ResourceTasksDistanceSingleTimePeriod2") task_1 = ps.FixedDurationTask("task1", duration=1) task_2 = ps.FixedDurationTask("task2", duration=1) worker_1 = ps.Worker("Worker1") task_1.add_required_resource(worker_1) task_2.add_required_resource(worker_1) ps.ResourceTasksDistance(worker_1, distance=4, mode="exact", list_of_time_intervals=[[10, 18]]) # force task 1 to start at 10 (in the time period intervak) ps.TaskStartAt(task_1, 10) # task_2 must be scheduled after task_1 ps.TaskPrecedence(task_1, task_2) # add a makespan objective, to be sure, to schedule task_2 in the time interal pb.add_objective_makespan() # as a consequence, task2 should be scheduled 4 periods after and start at 15 solver = ps.SchedulingSolver(pb) solution = solver.solve() self.assertTrue(solution) self.assertEqual(solution.tasks[task_2.name].start, 15) self.assertEqual(solution.tasks[task_2.name].end, 16)
def test_buffer_bounds_1(self) -> None: # n tasks take 1, n tasks feed one. Bounds 0 to 1 pb = ps.SchedulingProblem("BufferBounds1") n = 3 unloading_tasks = [ ps.FixedDurationTask("LoadTask_%i" % i, duration=3) for i in range(n) ] loading_tasks = [ ps.FixedDurationTask("UnloadTask_%i" % i, duration=3) for i in range(n) ] # create buffer buffer = ps.NonConcurrentBuffer("Buffer1", lower_bound=0, upper_bound=1) for t in unloading_tasks: ps.TaskUnloadBuffer(t, buffer, quantity=1) for t in loading_tasks: ps.TaskLoadBuffer(t, buffer, quantity=1) pb.add_objective_makespan() solver = ps.SchedulingSolver( pb, max_time=300, parallel=True) # , debug=True)#, logics="QF_UFIDL") solution = solver.solve() self.assertTrue(solution) self.assertEqual(solution.horizon, 9)
def test_resource_tasks_distance_2(self) -> None: pb = ps.SchedulingProblem("ResourceTasksDistance2") task_1 = ps.FixedDurationTask("task1", duration=8) task_2 = ps.FixedDurationTask("task2", duration=4) worker_1 = ps.Worker("Worker1") task_1.add_required_resource(worker_1) task_2.add_required_resource(worker_1) ps.ResourceTasksDistance(worker_1, distance=4, mode="max") ps.TaskStartAt(task_1, 1) pb.add_objective_makespan() solver = ps.SchedulingSolver(pb) solution = solver.solve() self.assertTrue(solution) t1_start = solution.tasks[task_1.name].start t2_start = solution.tasks[task_2.name].start t1_end = solution.tasks[task_1.name].end t2_end = solution.tasks[task_2.name].end self.assertEqual(t1_start, 1) self.assertEqual(t1_end, 9) self.assertEqual(t2_start, 9) self.assertEqual(t2_end, 13)
def test_schedule_three_tasks_three_alternative_workers(self) -> None: problem = ps.SchedulingProblem("ThreeTasksThreeSelectWorkers") # two tasks task_1 = ps.FixedDurationTask("task1", duration=3) task_2 = ps.FixedDurationTask("task2", duration=2) task_3 = ps.FixedDurationTask("task3", duration=2) # three workers worker_1 = ps.Worker("worker1") worker_2 = ps.Worker("worker2") worker_3 = ps.Worker("worker3") all_workers = [worker_1, worker_2, worker_3] task_1.add_required_resource(ps.SelectWorkers(all_workers, 1)) task_2.add_required_resource(ps.SelectWorkers(all_workers, 2)) task_3.add_required_resource(ps.SelectWorkers(all_workers, 3)) solution = _solve_problem(problem) self.assertTrue(solution) # each task should have one worker assigned self.assertEqual(len(solution.tasks[task_1.name].assigned_resources), 1) self.assertEqual(len(solution.tasks[task_2.name].assigned_resources), 2) self.assertEqual(len(solution.tasks[task_3.name].assigned_resources), 3)
def test_resource_tasks_distance_1(self) -> None: pb = ps.SchedulingProblem("ResourceTasksDistance1", horizon=20) task_1 = ps.FixedDurationTask("task1", duration=8) task_2 = ps.FixedDurationTask("task2", duration=4) worker_1 = ps.Worker("Worker1") task_1.add_required_resource(worker_1) task_2.add_required_resource(worker_1) c1 = ps.ResourceTasksDistance(worker_1, distance=4, mode="exact") pb.add_constraint(c1) pb.add_constraint(ps.TaskStartAt(task_1, 1)) solver = ps.SchedulingSolver(pb) solution = solver.solve() self.assertTrue(solution) t1_start = solution.tasks[task_1.name].start t2_start = solution.tasks[task_2.name].start t1_end = solution.tasks[task_1.name].end t2_end = solution.tasks[task_2.name].end self.assertEqual(t1_start, 1) self.assertEqual(t1_end, 9) self.assertEqual(t2_start, 13) self.assertEqual(t2_end, 17)
def test_resource_tasks_distance_single_time_period_1(self) -> None: """Adding one or more non scheduled optional tasks should not change anything""" pb = ps.SchedulingProblem("ResourceTasksDistanceSingleTimePeriod1") task_1 = ps.FixedDurationTask("task1", duration=1) task_2 = ps.FixedDurationTask("task2", duration=1) worker_1 = ps.Worker("Worker1") task_1.add_required_resource(worker_1) task_2.add_required_resource(worker_1) ps.ResourceTasksDistance(worker_1, distance=4, mode="exact", list_of_time_intervals=[[10, 18]]) ps.TaskPrecedence(task_1, task_2) # we add a makespan objective: the two tasks should be scheduled with an horizon of 2 # because they are outside the time period pb.add_objective_makespan() solver = ps.SchedulingSolver(pb) solution = solver.solve() self.assertTrue(solution) t1_start = solution.tasks[task_1.name].start t2_start = solution.tasks[task_2.name].start t1_end = solution.tasks[task_1.name].end t2_end = solution.tasks[task_2.name].end self.assertEqual(t1_start, 0) self.assertEqual(t1_end, 1) self.assertEqual(t2_start, 1) self.assertEqual(t2_end, 2)
def test_optional_cumulative(self): """Same as above, but with an optional taskand an horizon of 2. t2 should not be scheduled.""" pb_bs = ps.SchedulingProblem("OptionalCumulative", 2) # tasks t1 = ps.FixedDurationTask("T1", duration=2) t2 = ps.FixedDurationTask("T2", duration=2, optional=True) t3 = ps.FixedDurationTask("T3", duration=2) # workers r1 = ps.CumulativeWorker("Machine1", size=2) # resource assignment t1.add_required_resource(r1) t2.add_required_resource(r1) # constraints pb_bs.add_constraint(ps.TaskStartAt(t2, 1)) # plot solution solver = ps.SchedulingSolver(pb_bs) solution = solver.solve() self.assertTrue(solution) self.assertTrue(solution.tasks[t1.name].scheduled) self.assertTrue(solution.tasks[t3.name].scheduled) self.assertFalse(solution.tasks[t2.name].scheduled)
def build_complex_problem(name: str, n: int) -> ps.SchedulingProblem: """returns a problem with n tasks and n * 3 workers""" problem = ps.SchedulingProblem(name) nb_mandatory_tasks = 3 * n nb_optional_tasks = n nb_workers = 4 * n mandatory_tasks = [ ps.FixedDurationTask("mand_task%i" % i, duration=i % 8 + 1) for i in range(nb_mandatory_tasks) ] # n/10 optional tasks optional_tasks = [ ps.FixedDurationTask("opt_task%i" % i, duration=i % 8 + 1, optional=True) for i in range(nb_optional_tasks) ] all_tasks = mandatory_tasks + optional_tasks workers = [ps.Worker("task%i" % i) for i in range(nb_workers)] # for each task, add three single required workers for i, task in enumerate(all_tasks): j = i + 1 # an overlap task.add_required_resources(workers[j - 1:i + 3]) return problem
def test_resource_tasks_distance_3(self) -> None: pb = ps.SchedulingProblem("ResourceTasksDistanceContiguous3") task_1 = ps.FixedDurationTask("task1", duration=8) task_2 = ps.FixedDurationTask("task2", duration=4) task_3 = ps.FixedDurationTask("task3", duration=5) worker_1 = ps.Worker("Worker1") task_1.add_required_resource(worker_1) task_2.add_required_resource(worker_1) task_3.add_required_resource(worker_1) # a constraint to tell tasks are contiguous ps.ResourceTasksDistance(worker_1, distance=0, mode="exact") ps.TaskStartAt(task_1, 2) pb.add_objective_makespan() solver = ps.SchedulingSolver(pb) solution = solver.solve() self.assertTrue(solution) t1_start = solution.tasks[task_1.name].start t2_start = solution.tasks[task_2.name].start t3_start = solution.tasks[task_3.name].start t1_end = solution.tasks[task_1.name].end self.assertEqual(t1_start, 2) self.assertEqual(t1_end, 10) self.assertTrue(t3_start in [10, 14]) self.assertTrue(t2_start in [10, 15])
def test_load_buffer_2(self) -> None: pb = ps.SchedulingProblem("LoadBuffer2") task_1 = ps.FixedDurationTask("task1", duration=3) task_2 = ps.FixedDurationTask("task2", duration=3) task_3 = ps.FixedDurationTask("task3", duration=3) buffer = ps.NonConcurrentBuffer("Buffer1", initial_state=10) pb.add_constraint(ps.TaskStartAt(task_1, 5)) pb.add_constraint(ps.TaskStartAt(task_2, 10)) pb.add_constraint(ps.TaskStartAt(task_3, 15)) c1 = ps.TaskLoadBuffer(task_1, buffer, quantity=3) pb.add_constraint(c1) c2 = ps.TaskLoadBuffer(task_2, buffer, quantity=2) pb.add_constraint(c2) c3 = ps.TaskLoadBuffer(task_3, buffer, quantity=1) pb.add_constraint(c3) solver = ps.SchedulingSolver(pb) solution = solver.solve() self.assertTrue(solution) self.assertEqual(solution.buffers[buffer.name].state, [10, 13, 15, 16]) self.assertEqual(solution.buffers[buffer.name].state_change_times, [8, 13, 18])
def test_non_dynamic_1(self) -> None: # same test as previously # but the task_1 workers are non dynamic. # so the horizon must be 20. pb = ps.SchedulingProblem("NonDynamicTest1") task_1 = ps.FixedDurationTask("task1", duration=10, work_amount=10) task_2 = ps.FixedDurationTask("task2", duration=5) task_3 = ps.FixedDurationTask("task3", duration=5) pb.add_constraint(ps.TaskStartAt(task_3, 0)) pb.add_constraint(ps.TaskEndAt(task_2, 10)) worker_1 = ps.Worker("Worker1", productivity=1) worker_2 = ps.Worker("Worker2", productivity=1) task_1.add_required_resources([worker_1, worker_2]) # dynamic False by default task_2.add_required_resource(worker_1) task_3.add_required_resource(worker_2) pb.add_objective_makespan() solver = ps.SchedulingSolver(pb) solution = solver.solve() self.assertEqual(solution.horizon, 20)
def get_single_resource_utilization_problem(self, problem_name): problem = ps.SchedulingProblem("IndicatorFlowtimeSingleResource1", horizon=50) dur1 = 5 dur2 = 5 dur3 = 4 dur4 = 3 dur5 = 2 t_1 = ps.FixedDurationTask("T1", duration=dur1) t_2 = ps.FixedDurationTask("T2", duration=dur2) t_3 = ps.FixedDurationTask("T3", duration=dur3) t_4 = ps.FixedDurationTask("T4", duration=dur4) t_5 = ps.FixedDurationTask("T5", duration=dur5) worker_1 = ps.Worker("Worker1") t_1.add_required_resource(worker_1) t_2.add_required_resource(worker_1) t_3.add_required_resource(worker_1) t_4.add_required_resource(worker_1) t_5.add_required_resource(worker_1) ps.TaskEndBeforeLax(t_3, 35) ps.TaskEndBeforeLax(t_2, 35) ps.TaskEndBeforeLax(t_1, 35) ps.TaskEndBeforeLax(t_4, 35) ps.TaskEndBeforeLax(t_5, 35) ps.TaskStartAfterLax(t_3, 10) ps.TaskStartAfterLax(t_2, 10) ps.TaskStartAfterLax(t_1, 10) ps.TaskStartAfterLax(t_4, 10) ps.TaskStartAfterLax(t_5, 10) return problem, worker_1, dur1 + dur2 + dur3 + dur4 + dur5
def test_resource_utilization_indicator_2(self) -> None: """Two tasks, two workers.""" problem = ps.SchedulingProblem("IndicatorUtilization2", horizon=10) t_1 = ps.FixedDurationTask("T1", duration=5) t_2 = ps.FixedDurationTask("T2", duration=5) worker_1 = ps.Worker("Worker1") worker_2 = ps.Worker("Worker2") t_1.add_required_resource(worker_1) t_2.add_required_resource(ps.SelectWorkers([worker_1, worker_2])) utilization_res_1 = problem.add_indicator_resource_utilization( worker_1) utilization_res_2 = problem.add_indicator_resource_utilization( worker_2) solution = ps.SchedulingSolver(problem).solve() self.assertTrue(solution) result_res_1 = solution.indicators[utilization_res_1.name] result_res_2 = solution.indicators[utilization_res_2.name] # sum should be 100 self.assertEqual(result_res_1 + result_res_2, 100)
def test_multi_constraintsp(self) -> None: # we want to schedule one task in slot [1,5] and one task into slot [7, 12] pb = ps.SchedulingProblem( "ScheduleNTasksInTimeIntervalsMultipleConstraints", horizon=20 ) task_1 = ps.FixedDurationTask("task1", duration=3) task_2 = ps.FixedDurationTask("task2", duration=3) ps.ScheduleNTasksInTimeIntervals( [task_1, task_2], nb_tasks_to_schedule=1, list_of_time_intervals=[[1, 5]] ) ps.ScheduleNTasksInTimeIntervals( [task_1, task_2], nb_tasks_to_schedule=1, list_of_time_intervals=[[7, 12]] ) solver = ps.SchedulingSolver(pb) solution = solver.solve() self.assertTrue(solution) # check the solution task1_start = solution.tasks[task_1.name].start task1_end = solution.tasks[task_1.name].end task2_start = solution.tasks[task_2.name].start task2_end = solution.tasks[task_2.name].end task1_in_interval_1 = task1_start >= 1 and task1_end <= 5 task2_in_interval_1 = task2_start >= 1 and task2_end <= 5 self.assertTrue(task1_in_interval_1 != task2_in_interval_1) # xor task1_in_interval_2 = task1_start >= 7 and task1_end <= 12 task2_in_interval_2 = task2_start >= 7 and task2_end <= 12 self.assertTrue(task1_in_interval_2 != task2_in_interval_2) # xor self.assertTrue(task1_in_interval_1 != task2_in_interval_1) # xor self.assertTrue(task1_in_interval_2 != task2_in_interval_2) # xor
def test_all_same_distinct_workers(self): pb = ps.SchedulingProblem("AllSameDistinctWorkers") task_1 = ps.FixedDurationTask("task1", duration=2) task_2 = ps.FixedDurationTask("task2", duration=2) task_3 = ps.FixedDurationTask("task3", duration=2) task_4 = ps.FixedDurationTask("task4", duration=2) worker_1 = ps.Worker("John") worker_2 = ps.Worker("Bob") res_for_t1 = ps.SelectWorkers([worker_1, worker_2], 1) res_for_t2 = ps.SelectWorkers([worker_1, worker_2], 1) res_for_t3 = ps.SelectWorkers([worker_1, worker_2], 1) res_for_t4 = ps.SelectWorkers([worker_1, worker_2], 1) task_1.add_required_resource(res_for_t1) task_2.add_required_resource(res_for_t2) task_3.add_required_resource(res_for_t3) task_4.add_required_resource(res_for_t4) ps.SameWorkers(res_for_t1, res_for_t2) ps.SameWorkers(res_for_t3, res_for_t4) ps.DistinctWorkers(res_for_t2, res_for_t4) solver = ps.SchedulingSolver(pb) solution = solver.solve() self.assertTrue(solution) self.assertEqual(solution.horizon, 4)
def test_tasks_contiguous(self) -> None: pb = ps.SchedulingProblem("TasksContiguous") n = 7 tasks_w1 = [ ps.FixedDurationTask("t_w1_%i" % i, duration=3) for i in range(n) ] tasks_w2 = [ ps.FixedDurationTask("t_w2_%i" % i, duration=5) for i in range(n) ] worker_1 = ps.Worker("Worker1") worker_2 = ps.Worker("Worker2") for t in tasks_w1: t.add_required_resource(worker_1) for t in tasks_w2: t.add_required_resource(worker_2) c1 = ps.TasksContiguous(tasks_w1 + tasks_w2) pb.add_constraint(c1) pb.add_objective_makespan() solver = ps.SchedulingSolver(pb) solution = solver.solve() self.assertTrue(solution) self.assertEqual(solution.horizon, 56)
def test_resource_utilization_maximization_incremental_1(self) -> None: """Same as above, but both workers are selectable. Force one with resource utilization maximization objective.""" problem = ps.SchedulingProblem("IndicatorMaximizeIncremental", horizon=10) t_1 = ps.FixedDurationTask("T1", duration=5) t_2 = ps.FixedDurationTask("T2", duration=5) worker_1 = ps.Worker("Worker1") worker_2 = ps.Worker("Worker2") t_1.add_required_resource(ps.SelectWorkers([worker_1, worker_2])) t_2.add_required_resource(ps.SelectWorkers([worker_1, worker_2])) utilization_res_1 = problem.add_indicator_resource_utilization(worker_1) utilization_res_2 = problem.add_indicator_resource_utilization(worker_2) problem.maximize_indicator(utilization_res_1) solver = ps.SchedulingSolver(problem) solution = solver.solve() self.assertTrue(solution) self.assertEqual(solution.indicators[utilization_res_1.name], 100) self.assertEqual(solution.indicators[utilization_res_2.name], 0)
def test_resource_tasks_distance_4(self) -> None: """Adding one or more non scheduled optional tasks should not change anything""" pb = ps.SchedulingProblem("ResourceTasksDistance4OptionalTasks", horizon=20) task_1 = ps.FixedDurationTask("task1", duration=8) task_2 = ps.FixedDurationTask("task2", duration=4) task_3 = ps.FixedDurationTask("task3", duration=3, optional=True) task_4 = ps.FixedDurationTask("task4", duration=2, optional=True) task_5 = ps.FixedDurationTask("task5", duration=1, optional=True) worker_1 = ps.Worker("Worker1") task_1.add_required_resource(worker_1) task_2.add_required_resource(worker_1) ps.ResourceTasksDistance(worker_1, distance=4, mode="exact") ps.TaskStartAt(task_1, 1) solver = ps.SchedulingSolver(pb) # for optional tasks to not be scheduled solver.append_z3_assertion(task_3.scheduled == False) solver.append_z3_assertion(task_4.scheduled == False) solver.append_z3_assertion(task_5.scheduled == False) solution = solver.solve() self.assertTrue(solution) t1_start = solution.tasks[task_1.name].start t2_start = solution.tasks[task_2.name].start t1_end = solution.tasks[task_1.name].end t2_end = solution.tasks[task_2.name].end self.assertEqual(t1_start, 1) self.assertEqual(t1_end, 9) self.assertEqual(t2_start, 13) self.assertEqual(t2_end, 17)
def test_create_task_precedence_raise_exception_offset_int(self) -> None: new_problem_or_clear() t_1 = ps.FixedDurationTask("t1", duration=2) t_2 = ps.FixedDurationTask("t2", duration=3) with self.assertRaises(ValueError): ps.TaskPrecedence(t_1, t_2, offset=1.5, kind="lax") # should be int
def test_create_task_precedence_tight(self) -> None: new_problem_or_clear() t_1 = ps.FixedDurationTask("t1", duration=2) t_2 = ps.FixedDurationTask("t2", duration=3) precedence_constraint = ps.TaskPrecedence(t_1, t_2, offset=1, kind="tight") self.assertIsInstance(precedence_constraint, ps.TaskPrecedence)
def test_if_then_else(self) -> None: new_problem_or_clear() t_1 = ps.FixedDurationTask("t1", 2) t_2 = ps.FixedDurationTask("t2", 2) ite_constraint = ps.if_then_else( t_1.start == 1, # condition [ps.TaskStartAt(t_2, 3)], # then [ps.TaskStartAt(t_2, 6)], ) # else self.assertIsInstance(ite_constraint, ps.BoolRef)
def test_tasks_end_sync(self) -> None: pb = ps.SchedulingProblem("TasksEndSync") t_1 = ps.FixedDurationTask("t1", duration=2) t_2 = ps.FixedDurationTask("t2", duration=3) ps.TasksEndSynced(t_1, t_2) solver = ps.SchedulingSolver(pb) solution = solver.solve() self.assertTrue(solution) self.assertEqual(solution.tasks[t_1.name].end, solution.tasks[t_2.name].end)
def test_tasks_dont_overlap(self) -> None: pb = ps.SchedulingProblem("TasksDontOverlap") t_1 = ps.FixedDurationTask("t1", duration=7) t_2 = ps.FixedDurationTask("t2", duration=11) ps.TasksDontOverlap(t_1, t_2) pb.add_objective_makespan() solver = ps.SchedulingSolver(pb) solution = solver.solve() self.assertTrue(solution) self.assertEqual(solution.horizon, 18)
def test_create_task_precedence_strict(self) -> None: pb = ps.SchedulingProblem("TaskPrecedenceStrict") t_1 = ps.FixedDurationTask("t1", duration=2) t_2 = ps.FixedDurationTask("t2", duration=3) ps.TaskPrecedence(t_1, t_2, offset=1, kind="strict") pb.add_objective_makespan() solver = ps.SchedulingSolver(pb) solution = solver.solve() self.assertTrue(solution) self.assertEqual(solution.tasks[t_2.name].start, solution.tasks[t_1.name].end + 2)
def test_tasks_start_sync(self) -> None: pb = ps.SchedulingProblem("TasksStartSync") t_1 = ps.FixedDurationTask("t1", duration=2) t_2 = ps.FixedDurationTask("t2", duration=3) pb.add_constraint(ps.TaskStartAt(t_1, 7)) pb.add_constraint(ps.TasksStartSynced(t_1, t_2)) solver = ps.SchedulingSolver(pb) solution = solver.solve() self.assertTrue(solution) self.assertEqual(solution.tasks[t_1.name].start, solution.tasks[t_2.name].start)
def test_indicator_flowtime(self) -> None: problem = ps.SchedulingProblem("IndicatorFlowTime", horizon=2) t_1 = ps.FixedDurationTask("t1", 2) t_2 = ps.FixedDurationTask("t2", 2) i_1 = ps.Indicator("FlowTime", t_1.end + t_2.end) solution = ps.SchedulingSolver(problem).solve() self.assertTrue(solution) self.assertEqual(solution.indicators[i_1.name], 4)
def test_optional_task_dependency_3(self) -> None: """Type checking.""" pb = ps.SchedulingProblem("OptionalDependency3", horizon=9) task_1 = ps.FixedDurationTask("task1", duration=5) # mandatory task_2 = ps.FixedDurationTask("task2", duration=4) # mandatory task_3 = ps.FixedDurationTask("task3", duration=1) # mandatory with self.assertRaises(TypeError): ps.OptionalTaskConditionSchedule(task_1, pb.horizon > 10) with self.assertRaises(TypeError): ps.OptionalTasksDependency(task_2, task_3)
def test_single_interval_too_small(self) -> None: # no way to schedule tasks with duration 3 in a slot with range 2 pb = ps.SchedulingProblem("ScheduleNTasksInTimeIntervalsTooSmall", horizon=20) task_1 = ps.FixedDurationTask("task1", duration=3) task_2 = ps.FixedDurationTask("task2", duration=3) ps.ScheduleNTasksInTimeIntervals( [task_1, task_2], nb_tasks_to_schedule=2, list_of_time_intervals=[[10, 12]] ) solver = ps.SchedulingSolver(pb) solution = solver.solve() self.assertFalse(solution)
def test_implies(self): problem = ps.SchedulingProblem("Implies", horizon=6) # only one task, the solver should schedule a start time at 0 task_1 = ps.FixedDurationTask("task1", duration=2) task_2 = ps.FixedDurationTask("task2", duration=2) ps.TaskStartAt(task_1, 1) fol_1 = ps.implies(task_1.start == 1, [ps.TaskStartAt(task_2, 4)]) problem.add_constraint(fol_1) solution = _solve_problem(problem) self.assertTrue(solution) # the only solution is to start at 2 self.assertTrue(solution.tasks[task_1.name].start == 1) self.assertTrue(solution.tasks[task_2.name].start == 4)
def test_single_interval_no_solution(self) -> None: pb = ps.SchedulingProblem("ScheduleNTasksInTimeIntervalsNoSolution", horizon=20) task_1 = ps.FixedDurationTask("task1", duration=3) task_2 = ps.FixedDurationTask("task2", duration=3) ps.ScheduleNTasksInTimeIntervals( [task_1, task_2], nb_tasks_to_schedule=3, # impossible!! list_of_time_intervals=[[10, 20]], ) solver = ps.SchedulingSolver(pb) solution = solver.solve() self.assertFalse(solution)