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_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_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_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_start_latest(self): problem = ps.SchedulingProblem("SolveStartLatest", horizon=51) # 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=3) ps.TaskPrecedence(task_1, task_2) problem.add_objective_start_latest() solution = _solve_problem(problem) self.assertTrue(solution) # check that the task is not scheduled to start à 0 # the only solution is 1 self.assertEqual(solution.tasks[task_1.name].start, 51 - (3 + 2)) self.assertEqual(solution.tasks[task_2.name].start, 51 - 3)
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_optional_tasks_precedence_2(self) -> None: """Task 2 cannot be scheduled.""" pb = ps.SchedulingProblem("OptionalTasksPrecedence2", horizon=8) task_1 = ps.FixedDurationTask("task1", duration=3) # mandatory task_2 = ps.FixedDurationTask("task2", duration=4, optional=True) # optional pb.add_constraint(ps.TaskStartAt(task_1, 0)) pb.add_constraint(ps.TaskPrecedence(task_1, task_2, offset=2)) solver = ps.SchedulingSolver(pb) solution = solver.solve() self.assertTrue(solution) self.assertTrue(solution.tasks[task_1.name].scheduled) self.assertFalse(solution.tasks[task_2.name].scheduled) self.assertEqual(solution.tasks[task_1.name].start, 0) self.assertEqual(solution.tasks[task_1.name].end, 3)
def test_schedule_two_fixed_duration_task_with_precedence(self) -> None: problem = ps.SchedulingProblem("TwoFixedDurationTasksWithPrecedence", horizon=5) task_1 = ps.FixedDurationTask("task1", duration=2) task_2 = ps.FixedDurationTask("task2", duration=3) # add two constraints to set start and end ps.TaskStartAt(task_1, 0) ps.TaskPrecedence(task_before=task_1, task_after=task_2) solution = _solve_problem(problem) self.assertTrue(solution) task_1_solution = solution.tasks[task_1.name] task_2_solution = solution.tasks[task_2.name] self.assertEqual(task_1_solution.start, 0) self.assertEqual(task_1_solution.end, 2) self.assertEqual(task_2_solution.start, 2) self.assertEqual(task_2_solution.end, 5)
def test_optional_tasks_precedence_1(self) -> None: """Tasks can be scheduled.""" pb = ps.SchedulingProblem("OptionalTasksPrecedence1", horizon=9) task_1 = ps.FixedDurationTask("task1", duration=3) # mandatory task_2 = ps.FixedDurationTask("task2", duration=4, optional=True) # optional pb.add_constraint(ps.TaskStartAt(task_1, 0)) pb.add_constraint(ps.TaskPrecedence(task_1, task_2, offset=2)) # Force schedule, otherwise by default it is not scheduled pb.add_constraint(task_2.scheduled == True) solver = ps.SchedulingSolver(pb) solution = solver.solve() self.assertTrue(solution) self.assertTrue(solution.tasks[task_1.name].scheduled) self.assertTrue(solution.tasks[task_2.name].scheduled) self.assertEqual(solution.tasks[task_1.name].start, 0) self.assertEqual(solution.tasks[task_1.name].end, 3) self.assertEqual(solution.tasks[task_2.name].start, 5) self.assertEqual(solution.tasks[task_2.name].end, 9)
print("-> Problem size:", problem_size) # Teams and Resources init_time = time.perf_counter() pb = ps.SchedulingProblem("n_queens_type_scheduling", horizon=problem_size) R = {i: ps.Worker("W-%i" % i) for i in range(problem_size)} T = { (i, j): ps.FixedDurationTask("T-%i-%i" % (i, j), duration=1) for i in range(n) for j in range(problem_size) } # precedence constrains for i in range(problem_size): for j in range(1, problem_size): ps.TaskPrecedence(T[i, j - 1], T[i, j], offset=0) # resource assignment modulo n for j in range(problem_size): for i in range(problem_size): T[(i + j) % problem_size, j].add_required_resource(R[i]) # create the solver and solve solver = ps.SchedulingSolver(pb, max_time=mt, logics=args.logics) solution = solver.solve() if not solution: break computation_times.append(time.perf_counter() - init_time) plot_abs.append(problem_size)