Skip to content

Commit e9fcf88

Browse files
committed
v0.2.5 New example (Employee Scheduling), boiler plate code for OOP approach, little fixes
1 parent 6bd4dd1 commit e9fcf88

37 files changed

+967
-9
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
/.vscode
33
/greyjack/target
44
/data
5+
/examples/object_oriented/project_job_shop
56

67
# Byte-compiled / optimized / DLL files
78
__pycache__/

examples/object_oriented/boiler_plate_code/__init__.py

Whitespace-only changes.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
2+
3+
from greyjack.cotwin.CotwinBase import CotwinBase
4+
5+
class Cotwin(CotwinBase):
6+
def __init__(self):
7+
super().__init__()

examples/object_oriented/boiler_plate_code/cotwin/__init__.py

Whitespace-only changes.

examples/object_oriented/boiler_plate_code/domain/__init__.py

Whitespace-only changes.
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
2+
3+
4+
from greyjack.persistence.CotwinBuilderBase import CotwinBuilderBase
5+
from greyjack.variables.GJInteger import GJInteger
6+
from examples.object_oriented.boiler_plate_code.cotwin.Cotwin import Cotwin
7+
from examples.object_oriented.boiler_plate_code.score.IncrementalScoreCalculator import IncrementalScoreCalculator
8+
from examples.object_oriented.boiler_plate_code.score.PlainScoreCalculator import PlainScoreCalculator
9+
10+
11+
class CotwinBuilder(CotwinBuilderBase):
12+
def __init__(self, use_incremental_score_calculator, use_greed_init):
13+
self.use_incremental_score_calculator = use_incremental_score_calculator
14+
self.use_greed_init = use_greed_init
15+
pass
16+
17+
def build_cotwin(self, domain, is_already_initialized):
18+
19+
cotwin = Cotwin()
20+
21+
cotwin.add_planning_entities_list(self._build_some_planning_entities(domain, is_already_initialized), "some_planning_entities")
22+
#cotwin.add_problem_facts_list(self._build_some_problem_facts(domain), "some_problem_facts")
23+
24+
if self.use_incremental_score_calculator:
25+
score_calculator = IncrementalScoreCalculator()
26+
else:
27+
score_calculator = PlainScoreCalculator()
28+
29+
cotwin.set_score_calculator( score_calculator )
30+
31+
return cotwin
32+
33+
34+
35+
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
2+
import random
3+
4+
from greyjack.persistence.DomainBuilderBase import DomainBuilderBase
5+
6+
class DomainBuilder(DomainBuilderBase):
7+
8+
def __init__(self, random_seed=45):
9+
super().__init__()
10+
11+
self.random_seed = random_seed
12+
13+
def build_domain_from_scratch(self):
14+
return domain
15+
16+
def build_from_solution(self, solution, initial_domain=None):
17+
return domain
18+
19+
def build_from_domain(self, domain):
20+
return super().build_from_domain(domain)
21+
22+
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2+
3+
4+
from greyjack.persistence.DomainBuilderBase import DomainBuilderBase
5+
from greyjack.persistence.CotwinBuilderBase import CotwinBuilderBase
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
2+
from greyjack.score_calculation.score_calculators.IncrementalScoreCalculator import IncrementalScoreCalculator
3+
from greyjack.score_calculation.scores.SimpleScore import SimpleScore
4+
from greyjack.score_calculation.scores.ScoreVariants import ScoreVariants
5+
import polars as pl
6+
import numpy as np
7+
import numba
8+
from numba import jit, int64, float64, vectorize
9+
10+
11+
class IncrementalScoreCalculator(IncrementalScoreCalculator):
12+
def __init__(self):
13+
super().__init__()
14+
self.score_variant = ScoreVariants.SimpleScore
15+
self.add_constraint("some_constraint_function", self.some_constraint_function)
16+
pass
17+
18+
def some_constraint_function(self, planning_entity_dfs, problem_fact_dfs, delta_dfs):
19+
20+
return scores
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
2+
3+
from greyjack.score_calculation.score_calculators.PlainScoreCalculator import PlainScoreCalculator
4+
from greyjack.score_calculation.scores.SimpleScore import SimpleScore
5+
from greyjack.score_calculation.scores.ScoreVariants import ScoreVariants
6+
import polars as pl
7+
8+
9+
class PlainScoreCalculator(PlainScoreCalculator):
10+
def __init__(self):
11+
12+
super().__init__()
13+
14+
self.score_variant = ScoreVariants.SimpleScore
15+
16+
self.add_constraint("some_constraint_function", self.some_constraint_function)
17+
18+
pass
19+
20+
def some_constraint_function(self, planning_entity_dfs, problem_fact_dfs):
21+
22+
return scores

examples/object_oriented/boiler_plate_code/score/__init__.py

Whitespace-only changes.

examples/object_oriented/boiler_plate_code/scripts/__init__.py

Whitespace-only changes.
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
from pathlib import Path
2+
import os
3+
import sys
4+
5+
# To launch normally from console
6+
script_dir_path = Path(os.path.dirname(os.path.realpath(__file__)))
7+
project_dir_id = script_dir_path.parts.index("greyjack-solver-python")
8+
project_dir_path = Path(*script_dir_path.parts[:project_dir_id+1])
9+
sys.path.append(str(project_dir_path))
10+
11+
from examples.object_oriented.boiler_plate_code.persistence.DomainBuilder import DomainBuilder
12+
from examples.object_oriented.boiler_plate_code.persistence.CotwinBuilder import CotwinBuilder
13+
from greyjack.agents.termination_strategies import *
14+
from greyjack.agents import *
15+
from greyjack.SolverOOP import SolverOOP
16+
from greyjack.agents.base.LoggingLevel import LoggingLevel
17+
from greyjack.agents.base.ParallelizationBackend import ParallelizationBackend
18+
from greyjack.agents import *
19+
20+
if __name__ == "__main__":
21+
22+
# build domain model
23+
domain_builder = DomainBuilder(random_seed=45)
24+
cotwin_builder = CotwinBuilder(use_incremental_score_calculator=True)
25+
26+
#termination_strategy = StepsLimit(step_count_limit=1000)
27+
#termination_strategy = TimeSpentLimit(time_seconds_limit=60)
28+
#termination_strategy = ScoreNoImprovement(time_seconds_limit=15)
29+
termination_strategy = ScoreLimit(score_to_compare=[0])
30+
agent = TabuSearch(neighbours_count=20, tabu_entity_rate=0.0,
31+
mutation_rate_multiplier=None, move_probas=[0.5, 0.5, 0, 0, 0, 0],
32+
migration_frequency=10, termination_strategy=termination_strategy)
33+
"""agent = GeneticAlgorithm(population_size=128, crossover_probability=0.5, p_best_rate=0.05,
34+
tabu_entity_rate=0.0, mutation_rate_multiplier=1.0, move_probas=[0.5, 0.5, 0, 0, 0, 0],
35+
migration_rate=0.00001, migration_frequency=1, termination_strategy=termination_strategy)"""
36+
"""agent = LateAcceptance(late_acceptance_size=10, tabu_entity_rate=0.0,
37+
mutation_rate_multiplier=None, move_probas=[0.5, 0.5, 0, 0, 0, 0],
38+
compare_to_global_frequency=1, termination_strategy=termination_strategy)"""
39+
"""agent = SimulatedAnnealing(initial_temperature=[1.0], cooling_rate=0.9999, tabu_entity_rate=0.0,
40+
mutation_rate_multiplier=None, move_probas=[0.5, 0.5, 0, 0, 0, 0],
41+
migration_frequency=10, compare_to_global_frequency=10, termination_strategy=termination_strategy)"""
42+
43+
solver = SolverOOP(domain_builder, cotwin_builder, agent,
44+
ParallelizationBackend.Multiprocessing, LoggingLevel.FreshOnly,
45+
n_jobs=10, score_precision=[0])
46+
solution = solver.solve()
47+
48+
domain = domain_builder.build_from_solution(solution)
49+
print(domain)
50+
51+
print( "done" )

examples/object_oriented/cloud_balancing/persistence/CotwinBuilder.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,11 +43,12 @@ def _build_planning_processes(self, domain_model):
4343

4444
cot_processes = []
4545
n_computers = len(domain_model.computers)
46+
m_processes = len(domain_model.processes)
4647

4748
if self.use_greed_init:
4849
initial_computer_ids = self._build_greed_initial_computer_ids(domain_model)
4950
else:
50-
initial_computer_ids = n_computers * [None]
51+
initial_computer_ids = m_processes * [None]
5152

5253

5354
for i, process in enumerate(domain_model.processes):

examples/object_oriented/cloud_balancing/scripts/solve_cloud_balancing.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
"""agent = GeneticAlgorithm(population_size=128, crossover_probability=0.5, p_best_rate=0.2,
4343
tabu_entity_rate=0.2, mutation_rate_multiplier=1.0, move_probas=[0.5, 0.5, 0.0, 0.0, 0.0, 0.0],
4444
migration_rate=0.00001, migration_frequency=10, termination_strategy=termination_strategy)"""
45-
"""agent = LateAcceptance(late_acceptance_size=5, tabu_entity_rate=0.8,
45+
"""agent = LateAcceptance(late_acceptance_size=10, tabu_entity_rate=0.8,
4646
mutation_rate_multiplier=None, compare_to_global_frequency=10, move_probas=[0.5, 0.5, 0.0, 0.0, 0.0, 0.0],
4747
termination_strategy=termination_strategy)"""
4848
"""agent = SimulatedAnnealing(initial_temperature=[1.0, 1.0], cooling_rate=0.9999, tabu_entity_rate=0.8,

examples/object_oriented/employee_scheduling/__init__.py

Whitespace-only changes.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
2+
3+
4+
5+
class CotEmployee():
6+
7+
def __init__(self, id, name, skills, unavailable_dates, undesired_dates, desired_dates):
8+
9+
self.employee_id = id
10+
self.name = name
11+
self.skills = skills
12+
self.unavailable_dates = unavailable_dates
13+
self.undesired_dates = undesired_dates
14+
self.desired_dates = desired_dates
15+
16+
pass
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
2+
3+
class CotShift():
4+
5+
def __init__(self, id, start, end, location, required_skill, employee):
6+
7+
self.shift_id = id
8+
self.start = start
9+
self.end = end
10+
self.start_date = self.start.date()
11+
self.location = location
12+
self.required_skill = required_skill
13+
self.employee_id = employee
14+
15+
pass
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
2+
3+
from greyjack.cotwin.CotwinBase import CotwinBase
4+
5+
class Cotwin(CotwinBase):
6+
def __init__(self):
7+
super().__init__()

examples/object_oriented/employee_scheduling/cotwin/__init__.py

Whitespace-only changes.
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
2+
3+
4+
5+
class Employee():
6+
7+
def __init__(self, name, skills):
8+
9+
self.name = name
10+
self.skills = skills
11+
self.unavailable_dates = []
12+
self.undesired_dates = []
13+
self.desired_dates = []
14+
15+
pass
16+
17+
def __str__(self):
18+
19+
employee_info = "{} ({}) | Unavailable dates {} | Undesired dates {} | Desired dates {}".format(self.name, self.skills,
20+
self.unavailable_dates, self.undesired_dates,
21+
self.desired_dates)
22+
23+
24+
return employee_info
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
2+
3+
import numpy as np
4+
5+
class EmployeeSchedule():
6+
7+
def __init__(self, employees, shifts):
8+
9+
self.employees = employees
10+
self.shifts = shifts
11+
12+
pass
13+
14+
def print_schedule(self):
15+
16+
for shift in self.shifts:
17+
shift_assignment_info = str(shift) + " --> " + str(self.employees[shift.employee])
18+
print(shift_assignment_info)
19+
20+
def print_metrics(self):
21+
22+
unfairness_penalty = 0
23+
m_employees = len(self.employees)
24+
shifts_counts = np.zeros((m_employees,), np.int64)
25+
for shift in self.shifts:
26+
shifts_counts[shift.employee] += 1
27+
unfairness_penalty += np.sqrt(np.sum(np.square(shifts_counts - shifts_counts.mean())))
28+
29+
for i in range(m_employees):
30+
print("{} shifts count: {}".format(self.employees[i].name, shifts_counts[i]))
31+
print("Mean shifts count: {}".format(shifts_counts.mean()))
32+
print("Load balance coefficient: {}".format(unfairness_penalty))
33+
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
2+
3+
class Shift():
4+
5+
def __init__(self, id, start, end, location, required_skill):
6+
7+
self.id = id
8+
self.start = start
9+
self.end = end
10+
self.location = location
11+
self.required_skill = required_skill
12+
self.employee = None
13+
14+
pass
15+
16+
def __str__(self):
17+
18+
shift_info = "{}: {} - {} ({})".format(self.id, self.start, self.end, self.required_skill)
19+
20+
return shift_info
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
2+
3+
from .Employee import Employee
4+
from .EmployeeSchedule import EmployeeSchedule
5+
from .Shift import Shift

0 commit comments

Comments
 (0)