Skip to content

Commit

Permalink
introduce LFTScheduler and RandomizedLFTScheduler
Browse files Browse the repository at this point in the history
with tests
  • Loading branch information
Timotshak committed Nov 28, 2023
1 parent 10bba54 commit bde11e3
Show file tree
Hide file tree
Showing 8 changed files with 80 additions and 87 deletions.
1 change: 1 addition & 0 deletions sampo/scheduler/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ class SchedulerType(Enum):
Topological = 'topological'
HEFTAddEnd = 'heft_add_end'
HEFTAddBetween = 'heft_add_between'
LFT = 'LFT'


class Scheduler(ABC):
Expand Down
4 changes: 2 additions & 2 deletions sampo/scheduler/lft/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class LFTScheduler(Scheduler):
"""

def __init__(self,
scheduler_type: SchedulerType = SchedulerType.HEFTAddEnd,
scheduler_type: SchedulerType = SchedulerType.LFT,
timeline_type: Type = MomentumTimeline,
work_estimator: WorkTimeEstimator = DefaultWorkEstimator()):
super().__init__(scheduler_type, None, work_estimator)
Expand Down Expand Up @@ -204,7 +204,7 @@ class RandomizedLFTScheduler(LFTScheduler):
"""

def __init__(self,
scheduler_type: SchedulerType = SchedulerType.HEFTAddEnd,
scheduler_type: SchedulerType = SchedulerType.LFT,
timeline_type: Type = MomentumTimeline,
work_estimator: WorkTimeEstimator = DefaultWorkEstimator(),
rand: random.Random = random.Random()):
Expand Down
50 changes: 19 additions & 31 deletions tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,26 +55,14 @@ def setup_simple_synthetic(setup_rand) -> SimpleSynthetic:
return SimpleSynthetic(setup_rand)


@fixture(params=[(graph_type, lag) for lag in [
True,
False
]
for graph_type in [
'manual',
'small plain synthetic',
'big plain synthetic'
]],
@fixture(params=[(graph_type, lag) for lag in [True, False]
for graph_type in ['manual',
'small plain synthetic', 'big plain synthetic']],
# 'small advanced synthetic', 'big advanced synthetic']],
ids=[f'Graph: {graph_type}, LAG_OPT={lag_opt}'
for lag_opt in [
True,
False
]
for graph_type in [
'manual',
'small plain synthetic',
'big plain synthetic'
]])
for lag_opt in [True, False]
for graph_type in ['manual',
'small plain synthetic', 'big plain synthetic']])
# 'small advanced synthetic', 'big advanced synthetic']])
def setup_wg(request, setup_sampler, setup_simple_synthetic) -> WorkGraph:
SMALL_GRAPH_SIZE = 100
Expand All @@ -91,26 +79,26 @@ def setup_wg(request, setup_sampler, setup_simple_synthetic) -> WorkGraph:
s = get_start_stage()

l1n1 = sr.graph_node('l1n1', [(s, 0, EdgeType.FinishStart)], group='0', work_id='000001')
# l1n1.work_unit.material_reqs = [MaterialReq('mat1', 50)]
l1n1.work_unit.material_reqs = [MaterialReq('mat1', 50)]
l1n2 = sr.graph_node('l1n2', [(s, 0, EdgeType.FinishStart)], group='0', work_id='000002')
# l1n2.work_unit.material_reqs = [MaterialReq('mat1', 50)]
l1n2.work_unit.material_reqs = [MaterialReq('mat1', 50)]

l2n1 = sr.graph_node('l2n1', [(l1n1, 0, EdgeType.FinishStart)], group='1', work_id='000011')
# l2n1.work_unit.material_reqs = [MaterialReq('mat1', 50)]
l2n1.work_unit.material_reqs = [MaterialReq('mat1', 50)]
l2n2 = sr.graph_node('l2n2', [(l1n1, 0, EdgeType.FinishStart),
(l1n2, 0, EdgeType.FinishStart)], group='1', work_id='000012')
# l2n2.work_unit.material_reqs = [MaterialReq('mat1', 50)]
l2n2.work_unit.material_reqs = [MaterialReq('mat1', 50)]
l2n3 = sr.graph_node('l2n3', [(l1n2, 1, EdgeType.LagFinishStart)], group='1', work_id='000013')
# l2n3.work_unit.material_reqs = [MaterialReq('mat1', 50)]
l2n3.work_unit.material_reqs = [MaterialReq('mat1', 50)]

l3n1 = sr.graph_node('l3n1', [(l2n1, 0, EdgeType.FinishStart),
l3n1 = sr.graph_node('l2n1', [(l2n1, 0, EdgeType.FinishStart),
(l2n2, 0, EdgeType.FinishStart)], group='2', work_id='000021')
# l3n1.work_unit.material_reqs = [MaterialReq('mat1', 50)]
l3n2 = sr.graph_node('l3n2', [(l2n2, 0, EdgeType.FinishStart)], group='2', work_id='000022')
# l3n2.work_unit.material_reqs = [MaterialReq('mat1', 50)]
l3n3 = sr.graph_node('l3n3', [(l2n3, 1, EdgeType.LagFinishStart),
l3n1.work_unit.material_reqs = [MaterialReq('mat1', 50)]
l3n2 = sr.graph_node('l2n2', [(l2n2, 0, EdgeType.FinishStart)], group='2', work_id='000022')
l3n2.work_unit.material_reqs = [MaterialReq('mat1', 50)]
l3n3 = sr.graph_node('l2n3', [(l2n3, 1, EdgeType.LagFinishStart),
(l2n2, 0, EdgeType.FinishStart)], group='2', work_id='000023')
# l3n3.work_unit.material_reqs = [MaterialReq('mat1', 50)]
l3n3.work_unit.material_reqs = [MaterialReq('mat1', 50)]

f = get_finish_stage([l3n1, l3n2, l3n3])
wg = WorkGraph(s, f)
Expand Down Expand Up @@ -141,8 +129,8 @@ def setup_wg(request, setup_sampler, setup_simple_synthetic) -> WorkGraph:


# TODO Make parametrization with different(specialized) contractors
@fixture(params=[(i, 5 * j) for j in range(0,2) for i in range(1, 2)],
ids=[f'Contractors: count={i}, min_size={5 * j}' for j in range(0,2) for i in range(1, 2)])
@fixture(params=[(i, 5 * j) for j in range(2) for i in range(1, 2)],
ids=[f'Contractors: count={i}, min_size={5 * j}' for j in range(2) for i in range(1, 2)])
def setup_scheduler_parameters(request, setup_wg, setup_landscape_many_holders) -> tuple[
WorkGraph, list[Contractor], LandscapeConfiguration | Any]:
resource_req: Dict[str, int] = {}
Expand Down
55 changes: 1 addition & 54 deletions tests/scheduler/genetic/full_scheduling.py
Original file line number Diff line number Diff line change
@@ -1,65 +1,12 @@
from sampo.scheduler.genetic.base import GeneticScheduler
from sampo.scheduler.topological.base import TopologicalScheduler
from sampo.scheduler.lft.prioritization import lft_prioritization
from sampo.scheduler.heft.base import HEFTScheduler, HEFTBetweenScheduler
from sampo.utilities.validation import validate_schedule

import pandas as pd


def test_multiprocessing(setup_scheduler_parameters):
setup_wg, setup_contractors, setup_landscape = setup_scheduler_parameters

genetic = GeneticScheduler(number_of_generation=100,
genetic = GeneticScheduler(number_of_generation=10,
mutate_order=0.05,
mutate_resources=0.005,
size_of_population=50)

genetic.schedule(setup_wg, setup_contractors, landscape=setup_landscape)


def test_topological(setup_scheduler_parameters):
setup_wg, setup_contractors, setup_landscape = setup_scheduler_parameters

topological = TopologicalScheduler()

schedule = topological.schedule(setup_wg, setup_contractors, landscape=setup_landscape)

print(schedule.execution_time)


def test_lft_scheduling(setup_scheduler_parameters):
setup_wg, setup_contractors, setup_landscape = setup_scheduler_parameters

scheduler = HEFTScheduler()
schedule = scheduler.schedule(setup_wg, setup_contractors, validate=True, landscape=setup_landscape)
default_time = schedule.execution_time

scheduler = HEFTScheduler(prioritization_f=lft_prioritization)
schedule = scheduler.schedule(setup_wg, setup_contractors, validate=True, landscape=setup_landscape)
lft_time = schedule.execution_time

try:
validate_schedule(schedule, setup_wg, setup_contractors)

except AssertionError as e:
raise AssertionError(f'Scheduler {scheduler} failed validation', e)

print(default_time, lft_time)


def test_lft_scheduling2(setup_scheduler_parameters):
setup_wg, setup_contractors, setup_landscape = setup_scheduler_parameters

scheduler = HEFTBetweenScheduler()
schedule = scheduler.schedule(setup_wg, setup_contractors,
validate=True,
landscape=setup_landscape)
default_time = schedule.execution_time

try:
validate_schedule(schedule, setup_wg, setup_contractors)
except AssertionError as e:
raise AssertionError(f'Scheduler {scheduler} failed validation', e)

print(default_time)
Empty file added tests/scheduler/lft/__init__.py
Empty file.
18 changes: 18 additions & 0 deletions tests/scheduler/lft/fixtures.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from pytest import fixture

from sampo.scheduler.lft.base import LFTScheduler, RandomizedLFTScheduler
import random


@fixture(params=[LFTScheduler, RandomizedLFTScheduler],
ids=[f'Scheduler: {scheduler}' for scheduler in ['LFTScheduler', 'RandomizedLFTScheduler']])
def setup_schedulers_and_parameters(request, setup_scheduler_parameters) -> tuple:
scheduler = request.param
if isinstance(scheduler, RandomizedLFTScheduler):
scheduler = scheduler(rand=random.Random(2023))
else:
scheduler = scheduler()

setup_wg, setup_contractors, setup_landscape = setup_scheduler_parameters

return setup_wg, setup_contractors, setup_landscape, scheduler
21 changes: 21 additions & 0 deletions tests/scheduler/lft/prioritization_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
from sampo.scheduler.lft.prioritization import lft_prioritization
from sampo.schemas.graph import GraphNode
from sampo.schemas.contractor import get_worker_contractor_pool
from tests.scheduler.lft.fixtures import setup_schedulers_and_parameters


def test_correct_order(setup_schedulers_and_parameters):
setup_wg, setup_contractors, _, scheduler = setup_schedulers_and_parameters
worker_pool = get_worker_contractor_pool(setup_contractors)
_, node_id2duration = scheduler._contractor_workers_assignment(setup_wg, setup_contractors, worker_pool)
order = lft_prioritization(setup_wg, node_id2duration)
seen: set[GraphNode] = set()

for node in reversed(order):
if not node.children:
break
assert all([parent in seen for parent in node.parents])
seen.add(node)
while node.is_inseparable_parent():
node = node.inseparable_son
seen.add(node)
18 changes: 18 additions & 0 deletions tests/scheduler/lft/scheduling_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from sampo.utilities.validation import validate_schedule
from tests.scheduler.lft.fixtures import setup_schedulers_and_parameters


def test_lft_scheduling(setup_schedulers_and_parameters):
setup_wg, setup_contractors, setup_landscape, scheduler = setup_schedulers_and_parameters

schedule = scheduler.schedule(setup_wg, setup_contractors,
validate=True,
landscape=setup_landscape)
lft_time = schedule.execution_time

assert not lft_time.is_inf()

try:
validate_schedule(schedule, setup_wg, setup_contractors)
except AssertionError as e:
raise AssertionError(f'Scheduler {scheduler} failed validation', e)

0 comments on commit bde11e3

Please sign in to comment.