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_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_resource_tasks_distance_double_time_period_1(self) -> None: """1 resource, 4 tasks, two time intervals for the ResourceTaskDistance""" pb = ps.SchedulingProblem("ResourceTasksDistanceMultiTimePeriod1") tasks = [ ps.FixedDurationTask("task%i" % i, duration=1) for i in range(4) ] worker_1 = ps.Worker("Worker1") for t in tasks: t.add_required_resource(worker_1) ps.ResourceTasksDistance( worker_1, distance=4, mode="exact", list_of_time_intervals=[[10, 20], [30, 40]], ) # add a makespan objective, all tasks should be scheduled from 0 to 4 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.horizon, 4)
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_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_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_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_raise_1(self) -> None: # if only one task is assigned to the worker, a issue is raised ps.SchedulingProblem("ResourceTasksDistanceOneTaskRaiseAssertionError") worker = ps.Worker("worker") task = ps.FixedDurationTask("Task", 1) task.add_required_resource(worker) with self.assertRaises(AssertionError): ps.ResourceTasksDistance(worker, 0, [(0, 5)])
def test_json_export_1(self): pb = ps.SchedulingProblem("JSONExport1", horizon=10) # tasks task_1 = ps.FixedDurationTask("task1", duration=3) task_2 = ps.VariableDurationTask("task2") task_3 = ps.ZeroDurationTask("task3") # buffers buffer_1 = ps.NonConcurrentBuffer("Buffer1", initial_state=10) buffer_2 = ps.NonConcurrentBuffer("Buffer2", initial_state=0) # resources worker_1 = ps.Worker("Worker1") worker_2 = ps.Worker("Worker2") worker_3 = ps.Worker("Worker3") sw_1 = ps.SelectWorkers([worker_1, worker_2, worker_3]) sw_2 = ps.SelectWorkers([worker_1, worker_2, worker_3]) sw_3 = ps.SelectWorkers([worker_1, worker_2, worker_3]) ps.CumulativeWorker("CumulMachine1", size=3) ps.CumulativeWorker("CumulMachine2", size=7) # assign resources to tasks task_1.add_required_resources([worker_1, worker_2]) task_2.add_required_resource(sw_1) task_3.add_required_resource(sw_2) # task constraints ps.TaskPrecedence(task_1, task_2) ps.TaskStartAt(task_1, 5) ps.TaskUnloadBuffer(task_1, buffer_1, quantity=3) ps.TaskLoadBuffer(task_1, buffer_2, quantity=2) # resource constraints ps.SameWorkers(sw_1, sw_2) ps.DistinctWorkers(sw_2, sw_3) ps.WorkLoad(worker_1, {(0, 6): 3, (19, 24): 4}, kind="exact") ps.ResourceUnavailable(worker_1, [(1, 3), (6, 8)]) ps.ResourceTasksDistance(worker_1, distance=4, mode="exact", list_of_time_intervals=[[10, 18]]) # export to json solver = ps.SchedulingSolver(pb) ps.export_json_to_file(pb, solver, "test_export_1.json")
def test_resource_tasks_distance_double_time_period_2(self) -> None: """Same as above, but force the tasks to be scheduled within the time intervals""" pb = ps.SchedulingProblem("ResourceTasksDistanceMultiTimePeriod2") tasks = [ ps.FixedDurationTask("task%i" % i, duration=1) for i in range(4) ] worker_1 = ps.Worker("Worker1") for t in tasks: t.add_required_resource(worker_1) c1 = ps.ResourceTasksDistance(worker_1, distance=4, mode="exact", time_periods=[[10, 20], [30, 40]]) pb.add_constraint(c1) # add a makespan objective, all tasks should be scheduled from 0 to 4 pb.add_constraint(ps.TaskStartAt(tasks[0], 10)) pb.add_constraint(ps.TaskStartAfterLax(tasks[1], 10)) pb.add_constraint(ps.TaskEndBeforeLax(tasks[1], 20)) pb.add_constraint(ps.TaskStartAt(tasks[2], 30)) pb.add_constraint(ps.TaskStartAfterLax(tasks[3], 30)) pb.add_constraint(ps.TaskEndBeforeLax(tasks[3], 40)) # 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.horizon, 36) t0_start = solution.tasks[tasks[0].name].start t1_start = solution.tasks[tasks[1].name].start t2_start = solution.tasks[tasks[2].name].start t3_start = solution.tasks[tasks[3].name].start t0_end = solution.tasks[tasks[0].name].end t1_end = solution.tasks[tasks[1].name].end t2_end = solution.tasks[tasks[2].name].end t3_end = solution.tasks[tasks[3].name].end self.assertEqual(t0_start, 10) self.assertEqual(t0_end, 11) self.assertEqual(t1_start, 15) self.assertEqual(t1_end, 16) self.assertEqual(t2_start, 30) self.assertEqual(t2_end, 31) self.assertEqual(t3_start, 35) self.assertEqual(t3_end, 36)
def test_resource_tasks_distance_raise_1(self) -> None: # if no task is assigned to the worker, a issue is raised ps.SchedulingProblem("ResourceTasksDistanceNoTaskRaiseAssertionError") worker = ps.Worker("Worker") with self.assertRaises(AssertionError): ps.ResourceTasksDistance(worker, 0, [(0, 5)])