diff --git a/sampo/scheduler/generic.py b/sampo/scheduler/generic.py index a565f707..2acc2d7f 100644 --- a/sampo/scheduler/generic.py +++ b/sampo/scheduler/generic.py @@ -155,10 +155,14 @@ def build_scheduler(self, finish_time += start_time if index == len(ordered_nodes) - 1: # we are scheduling the work `end of the project` - start_time = max(start_time, timeline.zone_timeline.finish_statuses()) + finish_time, finalizing_zones = timeline.zone_timeline.finish_statuses() + start_time = max(start_time, finish_time) # apply work to scheduling timeline.schedule(node, node2swork, best_worker_team, contractor, work_spec, start_time, work_spec.assigned_time, assigned_parent_time, work_estimator) + if index == len(ordered_nodes) - 1: # we are scheduling the work `end of the project` + node2swork[node].zones_pre = finalizing_zones + return node2swork.values(), assigned_parent_time, timeline diff --git a/sampo/scheduler/genetic/converter.py b/sampo/scheduler/genetic/converter.py index 4bb3e710..35a674d5 100644 --- a/sampo/scheduler/genetic/converter.py +++ b/sampo/scheduler/genetic/converter.py @@ -154,12 +154,16 @@ def work_scheduled(args) -> bool: st = assigned_parent_time # this work should always have st = 0, so we just re-assign it if idx == len(works_order) - 1: # we are scheduling the work `end of the project` - st = max(st, timeline.zone_timeline.finish_statuses()) + finish_time, finalizing_zones = timeline.zone_timeline.finish_statuses() + st = max(start_time, finish_time) # finish using time spec timeline.schedule(node, node2swork, worker_team, contractor, work_spec, st, exec_time, assigned_parent_time, work_estimator) + if idx == len(works_order) - 1: # we are scheduling the work `end of the project` + node2swork[node].zones_pre = finalizing_zones + work_timeline.update_timeline(st, exec_time, None) return True return False diff --git a/sampo/scheduler/timeline/zone_timeline.py b/sampo/scheduler/timeline/zone_timeline.py index a8744c95..68c29266 100644 --- a/sampo/scheduler/timeline/zone_timeline.py +++ b/sampo/scheduler/timeline/zone_timeline.py @@ -271,8 +271,9 @@ def update_timeline(self, index: int, zones: list[Zone], start_time: Time, exec_ end_time=start_time)) return sworks - def append_statuses(self, zones: list[Zone]) -> Time: + def append_statuses(self, zones: list[Zone]) -> tuple[Time, list[ZoneTransition]]: global_finish_time = Time(0) + sworks = [] for zone in zones: state = self._timeline[zone.name] @@ -286,9 +287,17 @@ def append_statuses(self, zones: list[Zone]) -> Time: state.add(ScheduleEvent(Time.inf().value, EventType.START, latest_time, None, zone.status)) state.add(ScheduleEvent(Time.inf().value, EventType.END, finish_time, None, zone.status)) + if latest_status != zone.status and zone.status != 0: + # if we need to change status, record it + sworks.append(ZoneTransition(name=zone.name, + from_status=latest_status, + to_status=zone.status, + start_time=latest_time - change_cost, + end_time=latest_time)) + global_finish_time = max(global_finish_time, finish_time) - return global_finish_time + return global_finish_time, sworks - def finish_statuses(self) -> Time: + def finish_statuses(self) -> tuple[Time, list[ZoneTransition]]: return self.append_statuses([Zone(*v) for v in self._config.end_statuses]) diff --git a/tests/pipeline/basic_pipeline_test.py b/tests/pipeline/basic_pipeline_test.py index 22ff7172..d8036119 100644 --- a/tests/pipeline/basic_pipeline_test.py +++ b/tests/pipeline/basic_pipeline_test.py @@ -44,7 +44,9 @@ def test_plain_scheduling_with_no_sufficient_number_of_contractors(setup_wg, set try: SchedulingPipeline.create() \ .wg(setup_wg) \ - .contractors(setup_empty_contractors) + .contractors(setup_empty_contractors) \ + .schedule(HEFTScheduler()) \ + .finish() except NoSufficientContractorError: thrown = True