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_gantt_matplotlib_zero_duration_task(self): pb = ps.SchedulingProblem("GanttZeroDuration", horizon=10) ps.ZeroDurationTask("task1") solver = ps.SchedulingSolver(pb) solution = solver.solve() self.assertTrue(solution) solution.render_gantt_matplotlib(show_plot=False)
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_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_export_to_smt2(self): problem = build_complex_problem("SolveExportToSMT2", 50) solver = ps.SchedulingSolver(problem) solution = _solve_problem(problem) self.assertTrue(solution) solver.export_to_smt2("complex_problem.smt2") self.assertTrue(os.path.isfile("complex_problem.smt2"))
def test_gantt_matplotlib_base(self): """take the single task/single resource and display output""" problem = ps.SchedulingProblem("RenderSolution", horizon=7) task = ps.FixedDurationTask("task", duration=7) # problem.add_task(task) worker = ps.Worker("worker") # problem.add_resource(worker) task.add_required_resource(worker) solver = ps.SchedulingSolver(problem) solution = solver.solve() self.assertTrue(solution) # display solution, using both ascii or matplotlib solution.render_gantt_matplotlib( render_mode="Resource", show_plot=False, fig_filename="test_render_resources_matplotlib.svg", ) solution.render_gantt_matplotlib( render_mode="Task", show_plot=False, fig_filename="test_render_tasks_matplotlib.svg", ) self.assertTrue(os.path.isfile("test_render_resources_matplotlib.svg")) self.assertTrue(os.path.isfile("test_render_tasks_matplotlib.svg"))
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_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_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_indicator_flowtime_single_resource_6(self) -> None: # Mutliple time intervals (Currently fails for nb_time_intervals > 2, gantt to check total_flowtime is correct) nb_time_intervals = 7 time_interval_length = 13 # always > 5 horizon = nb_time_intervals * time_interval_length time_intervals = [ (i, i + time_interval_length) for i in range(0, horizon, time_interval_length) ] ( problem, worker_1, sum_durations, ) = self.get_single_resource_utilization_problem_2(time_intervals) for interval in time_intervals: problem.add_objective_flowtime_single_resource( worker_1, time_interval=interval ) solver = ps.SchedulingSolver(problem) solution = solver.solve() self.assertTrue(solution) self.assertEqual(sum_durations, self.get_sum_flowtime(solution))
def test_optimize_linear_cost_3(self) -> None: # same cost function as above, we minimize the cst, # the task should be scheduled at 0 (because the cost function increases) problem = ps.SchedulingProblem("OptimizeLinearCost3") t_1 = ps.FixedDurationTask("t1", duration=17) def real_cost_function(t): return 23.112 * t + 3.5 worker_1 = ps.Worker( "Worker1", cost=ps.PolynomialCostFunction(real_cost_function)) t_1.add_required_resource(worker_1) cost_ind = problem.add_indicator_resource_cost([worker_1]) problem.add_objective_resource_cost([worker_1]) solution = ps.SchedulingSolver(problem).solve() self.assertTrue(solution) # the task is scheduled at the beginning of the workplan self.assertEqual(solution.tasks[t_1.name].start, 0) # expected cost should be 3374 expected_cost = ( (real_cost_function(0) + real_cost_function(17)) * 17) / 2 # Because there are Int type conversions, the result may not be exactly # the one expected, let's assume 99% is a good approx. err = abs(solution.indicators[cost_ind.name] / expected_cost - 1) self.assertLessEqual(err, 0.01)
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 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_load_unload_feed_buffers_1(self) -> None: # one task that consumes and feed two different buffers pb = ps.SchedulingProblem("LoadUnloadBuffer1") task_1 = ps.FixedDurationTask("task1", duration=3) buffer_1 = ps.NonConcurrentBuffer("Buffer1", initial_state=10) buffer_2 = ps.NonConcurrentBuffer("Buffer2", initial_state=0) pb.add_constraint(ps.TaskStartAt(task_1, 5)) c1 = ps.TaskUnloadBuffer(task_1, buffer_1, quantity=3) pb.add_constraint(c1) c2 = ps.TaskLoadBuffer(task_1, buffer_2, quantity=2) pb.add_constraint(c2) solver = ps.SchedulingSolver(pb) solution = solver.solve() self.assertTrue(solution) self.assertEqual(solution.buffers[buffer_1.name].state, [10, 7]) self.assertEqual(solution.buffers[buffer_1.name].state_change_times, [5]) self.assertEqual(solution.buffers[buffer_2.name].state, [0, 2]) self.assertEqual(solution.buffers[buffer_2.name].state_change_times, [8]) # plot buffers solution.render_gantt_matplotlib(show_plot=False)
def test_incremental_optimizer_linear_cost_1(self) -> None: # same cost function as above, we minimize the cst, # the task should be scheduled at 0 (because the cost function increases) problem = ps.SchedulingProblem("IncrementalOptimizerLinearCost1", horizon=40) t_1 = ps.FixedDurationTask("t1", duration=17) # the task should be scheduled at the end def int_cost_function(t): return -23 * t + 321 worker_1 = ps.Worker("Worker1", cost=ps.PolynomialCostFunction(int_cost_function)) t_1.add_required_resource(worker_1) cost_ind = problem.add_indicator_resource_cost([worker_1]) problem.minimize_indicator(cost_ind) solver = ps.SchedulingSolver(problem, random_values=True) solution = solver.solve() self.assertTrue(solution) self.assertEqual(solution.tasks[t_1.name].start, 23)
def test_optimize_linear_cost_1(self) -> None: # same cost function as above, we minimize the cst, # the task should be scheduled at 0 (because the cost function increases) problem = ps.SchedulingProblem("OptimizeLinearCost1") t_1 = ps.FixedDurationTask("t1", duration=17) def int_cost_function(t): return 23 * t + 3 worker_1 = ps.Worker("Worker1", cost=ps.PolynomialCostFunction(int_cost_function)) t_1.add_required_resource(worker_1) cost_ind = problem.add_indicator_resource_cost([worker_1]) problem.add_objective_resource_cost([worker_1]) solution = ps.SchedulingSolver(problem).solve() self.assertTrue(solution) # the task is scheduled at the beginning of the workplan self.assertEqual(solution.tasks[t_1.name].start, 0) # expected cost should be 3374 expected_cost = int( ((int_cost_function(0) + int_cost_function(17)) * 17) / 2) self.assertEqual(solution.indicators[cost_ind.name], expected_cost)
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_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_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_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 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_optimize_linear_cost_2(self) -> None: # now we have a cost function that decreases over time, # then minimizing the cost should schedule the task at the end. # so we define an horizon for the problem problem = ps.SchedulingProblem("OptimizeLinear2", horizon=87) t_1 = ps.FixedDurationTask("t1", duration=13) # be sure however that this function is positive on the interval def int_cost_function(t): return 711 - 5 * t worker_1 = ps.Worker("Worker1", cost=ps.PolynomialCostFunction(int_cost_function)) t_1.add_required_resource(worker_1) cost_ind = problem.add_indicator_resource_cost([worker_1]) problem.add_objective_resource_cost([worker_1]) solution = ps.SchedulingSolver(problem).solve() self.assertTrue(solution) # the task is scheduled at the beginning of the workplan self.assertEqual(solution.tasks[t_1.name].start, 74) # expected cost should be 3374 expected_cost = int( ((int_cost_function(74) + int_cost_function(87)) * 13) / 2) self.assertEqual(solution.indicators[cost_ind.name], expected_cost)
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_solve_non_integer_max_time(self): """a stress test which""" problem = build_complex_problem("SolveMaxTime", 1000) problem.add_objective_makespan() # 0.5s is not enough to solve this problem max_time_solver = ps.SchedulingSolver(problem, max_time=0.05) solution = max_time_solver.solve() self.assertFalse(solution)
def test_gantt_matplotlib_no_resource(self): pb = ps.SchedulingProblem("GanttNoResource", horizon=10) ps.FixedDurationTask("task1", duration=3) solver = ps.SchedulingSolver(pb) solution = solver.solve() self.assertTrue(solution) solution.render_gantt_matplotlib(render_mode="Resource", show_plot=False)
def test_find_another_solution_solve_before(self): problem = ps.SchedulingProblem("FindAnotherSolutionSolveBefore", horizon=6) task_1 = ps.FixedDurationTask("task1", duration=2) solver = ps.SchedulingSolver(problem) result = solver.find_another_solution( task_1.start) # error, first have to solve self.assertFalse(result)
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_optional_task_end_at_2(self) -> None: """Task cannot be scheduled.""" pb = ps.SchedulingProblem("OptionalTaskEndAt2", horizon=2) task_1 = ps.FixedDurationTask("task1", duration=3, optional=True) pb.add_constraint(ps.TaskEndAt(task_1, 4)) solver = ps.SchedulingSolver(pb) solution = solver.solve() self.assertTrue(solution) self.assertFalse(solution.tasks[task_1.name].scheduled)