Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
39 changes: 39 additions & 0 deletions examples/rcpsp/run_cpsat_auto.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
from discrete_optimization.generic_tools.cp_tools import ParametersCp
from discrete_optimization.rcpsp.parser import get_data_available, parse_file
from discrete_optimization.rcpsp.solvers.cpsat_auto import CpSatAutoRcpspSolver


def cpsat_single_mode_makespan_optimization():
files_available = get_data_available()
file = [f for f in files_available if "j301_1.sm" in f][0]
rcpsp_problem = parse_file(file)
solver = CpSatAutoRcpspSolver(rcpsp_problem)
solver.init_model()
params_cp = ParametersCp.default_cpsat()
result = solver.solve(
parameters_cp=params_cp,
time_limit=10,
ortools_cpsat_solver_kwargs={"log_search_progress": True},
)
sol, fit = result.get_best_solution_fit()
print(rcpsp_problem.evaluate(sol), rcpsp_problem.satisfy(sol))


def cpsat_multi_mode_makespan_optimization():
files_available = get_data_available()
file = [f for f in files_available if "j1010_1.mm" in f][0]
rcpsp_problem = parse_file(file)
solver = CpSatAutoRcpspSolver(rcpsp_problem)
solver.init_model()
params_cp = ParametersCp.default_cpsat()
result = solver.solve(
parameters_cp=params_cp,
time_limit=10,
ortools_cpsat_solver_kwargs={"log_search_progress": True},
)
sol, fit = result.get_best_solution_fit()
print(rcpsp_problem.evaluate(sol), rcpsp_problem.satisfy(sol))


if __name__ == "__main__":
cpsat_single_mode_makespan_optimization()
13 changes: 7 additions & 6 deletions examples/rcpsp_blocking_resource/rcpsp_with_blocking_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
This shows how blocking constraints affect optimal schedules.
"""

from discrete_optimization.generic_tasks_tools.generic_scheduling_utils import Objective
from discrete_optimization.rcpsp.parser import get_data_available, parse_file
from discrete_optimization.rcpsp.solvers.cpsat_auto import (
CpSatAutoRcpspSolver,
Expand Down Expand Up @@ -47,7 +48,7 @@ def solve_and_compare():
sol1 = result1.get_best_solution()

if sol1 is not None:
print(f"Makespan: {base_problem.evaluate(sol1)['makespan']}")
print(f"Makespan: {base_problem.evaluate(sol1)[Objective.MAKESPAN]}")
print(f"Feasible: {base_problem.satisfy(sol1)}")
print()

Expand All @@ -72,7 +73,7 @@ def solve_and_compare():
print(f"Makespan: {problem_setup.evaluate(sol2)['makespan']}")
print(f"Feasible: {problem_setup.satisfy(sol2)}")
print(
f"Makespan increase: {problem_setup.evaluate(sol2)['makespan'] - base_problem.evaluate(sol1)['makespan']}"
f"Makespan increase: {problem_setup.evaluate(sol2)[Objective.MAKESPAN] - base_problem.evaluate(sol1)[Objective.MAKESPAN]}"
)
print()

Expand All @@ -94,10 +95,10 @@ def solve_and_compare():
sol3 = result3.get_best_solution()

if sol3 is not None:
print(f"Makespan: {problem_aggressive.evaluate(sol3)['makespan']}")
print(f"Makespan: {problem_aggressive.evaluate(sol3)[Objective.MAKESPAN]}")
print(f"Feasible: {problem_aggressive.satisfy(sol3)}")
print(
f"Makespan increase: {problem_aggressive.evaluate(sol3)['makespan'] - base_problem.evaluate(sol1)['makespan']}"
f"Makespan increase: {problem_aggressive.evaluate(sol3)[Objective.MAKESPAN] - base_problem.evaluate(sol1)[Objective.MAKESPAN]}"
)
else:
print(
Expand All @@ -123,10 +124,10 @@ def solve_and_compare():
sol4 = result4.get_best_solution()

if sol4 is not None:
print(f"Makespan: {problem_conservative.evaluate(sol4)['makespan']}")
print(f"Makespan: {problem_conservative.evaluate(sol4)[Objective.MAKESPAN]}")
print(f"Feasible: {problem_conservative.satisfy(sol4)}")
print(
f"Makespan increase: {problem_conservative.evaluate(sol4)['makespan'] - base_problem.evaluate(sol1)['makespan']}"
f"Makespan increase: {problem_conservative.evaluate(sol4)[Objective.MAKESPAN] - base_problem.evaluate(sol1)[Objective.MAKESPAN]}"
)
print()

Expand Down
1 change: 1 addition & 0 deletions examples/shop/run_osp.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,3 +78,4 @@ def run_cpmpy_osp():

if __name__ == "__main__":
run_osp()
run_cpmpy_osp()
125 changes: 118 additions & 7 deletions examples/workforce/scheduling/run_via_generic.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,19 @@
from discrete_optimization.generic_tools.transformation.transformation_solver import (
TransformationSolver,
)
from discrete_optimization.workforce.generators.resource_scenario import (
ParamsRandomness,
generate_scheduling_disruption,
)
from discrete_optimization.workforce.scheduling.parser import (
AllocSchedulingProblem,
get_data_available,
parse_json_to_problem,
)
from discrete_optimization.workforce.scheduling.solvers.cpsat_auto import (
CPSatAutoAllocSchedulingSolver,
ObjectivesEnum,
)
from discrete_optimization.workforce.scheduling.transformations.generic_scheduling_impl import (
WfSchedulingToGenericSchedulingTransformation,
)
Expand All @@ -42,13 +51,15 @@ def run_cpsat():
# problem.same_allocation = []
p = ParametersCp.default_cpsat()
p.nb_process = 12
obj_computer = [
obj
for obj in problem.get_list_objective_computer()
if obj.get_objective_name()
in [Objective.NB_UNARY_RESOURCES_USED, Objective.CUMUL_COST]
]
print(obj_computer)
solver = TransformationSolver(
transformation=WfSchedulingToGenericSchedulingTransformation(
objective=[
(Objective.NB_UNARY_RESOURCES_USED, -1000),
(Objective.DISPERSION_WORKLOAD, -1),
]
),
transformation=WfSchedulingToGenericSchedulingTransformation(obj_computer),
solver_brick=SubBrick(
GenericSchedulingAutoCpSatImplSolver,
{
Expand All @@ -68,5 +79,105 @@ def run_cpsat():
plotly_schedule_comparison(sol, sol, problem, display=True)


def run_cpsat_disrupted():
instance = [p for p in get_data_available() if "instance_64.json" in p][0]
problem = parse_json_to_problem(instance)
solver = CPSatAutoAllocSchedulingSolver(problem)
solver.init_model(
objectives=[ObjectivesEnum.NB_TEAMS], adding_redundant_cumulative=True
)
sol, _ = solver.solve(time_limit=2).get_best_solution_fit()
d = generate_scheduling_disruption(
original_scheduling_problem=problem,
original_solution=sol,
list_drop_resource=None,
params_randomness=ParamsRandomness(
lower_nb_disruption=1,
upper_nb_disruption=2,
lower_nb_teams=1,
upper_nb_teams=1,
),
)
new_problem: AllocSchedulingProblem = d["scheduling_problem"]
p = ParametersCp.default_cpsat()
p.nb_process = 12
from discrete_optimization.generic_tasks_tools.objectives.allocated_tasks import (
AllocatedTasksObjective,
)
from discrete_optimization.generic_tasks_tools.objectives.allocation_changes import (
AllocationSwitchObjectiveComputer,
)
from discrete_optimization.generic_tasks_tools.objectives.schedule_changes import (
ScheduleChangesComputer,
)
from discrete_optimization.generic_tasks_tools.objectives.unary_resource_used import (
UnaryResourcesUsedComputer,
)

obj_computer = [
AllocationSwitchObjectiveComputer(
problem=new_problem,
base_allocation_solution=sol,
weight_objective=1.0,
switch_on_cost={
t: {ur: 100 for ur in new_problem.unary_resources_list}
for t in new_problem.tasks_list
},
switch_off_cost={
t: {ur: 100 for ur in new_problem.unary_resources_list}
for t in new_problem.tasks_list
},
),
ScheduleChangesComputer(
problem=new_problem,
base_scheduling_solution=sol,
weight_objective=1,
cost_any_shift={t: 1 for t in new_problem.tasks_list},
cost_unit_deviation={t: 1 for t in new_problem.tasks_list},
),
AllocatedTasksObjective(problem=new_problem, weight_objective=-1000),
UnaryResourcesUsedComputer(
problem,
weight_objective=1,
weight_per_unary_resource={
ur: 1 for ur in new_problem.unary_resources_list
},
),
]
print(obj_computer)
solver = TransformationSolver(
transformation=WfSchedulingToGenericSchedulingTransformation(obj_computer),
solver_brick=SubBrick(
GenericSchedulingAutoCpSatImplSolver,
{
"time_limit": 100,
"exactly_one_unary_resource_per_task": True,
"parameters_cp": p,
"ortools_cpsat_solver_kwargs": {"log_search_progress": True},
},
),
source_problem=new_problem,
)
res = solver.solve(
callbacks=[ObjectiveGapStopper(0, 0), BasicStatsCallback()],
)
new_sol = res[-1][0]
print(
"Objectives :",
obj_computer[0].compute_objective(new_sol),
obj_computer[1].compute_objective(new_sol),
)
plotly_schedule_comparison(
base_solution=sol,
updated_solution=new_sol,
show_all_changes=True,
problem=d["scheduling_problem"],
use_color_map_per_task=False,
color_map_per_task={},
plot_team_breaks=True,
display=True,
)


if __name__ == "__main__":
run_cpsat()
run_cpsat_disrupted()
9 changes: 9 additions & 0 deletions src/discrete_optimization/flex_scheduling/problem.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@
from discrete_optimization.generic_tasks_tools.no_overlap import (
WithoutNoOverlapProblem,
)
from discrete_optimization.generic_tasks_tools.objectives.makespan import (
MakespanObjectiveComputer,
)
from discrete_optimization.generic_tasks_tools.objectives.objective_computer import (
ObjectiveComputer,
)
from discrete_optimization.generic_tasks_tools.resource_blocking import (
BlockingConstraintMetadata,
FlexibleGapBlockingConstraint,
Expand Down Expand Up @@ -562,6 +568,9 @@ def get_task_start_or_end_lower_bound(
return self.min_end_time[self.task_id_to_index[task]]
return 0

def get_list_objective_computer(self) -> list[ObjectiveComputer]:
return [MakespanObjectiveComputer(problem=self, weight_objective=1)]

def get_task_start_or_end_upper_bound(
self, task: Task, start_or_end: StartOrEnd
) -> int:
Expand Down
Loading