Skip to content
73 changes: 65 additions & 8 deletions examples/rcpsp/run_cpsat.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import logging

import numpy as np
from matplotlib import pyplot as plt

from discrete_optimization.datasets import get_data_home
from discrete_optimization.generic_tools.callbacks.loggers import (
Expand All @@ -14,19 +15,33 @@
from discrete_optimization.generic_tools.cp_tools import ParametersCp
from discrete_optimization.rcpsp.parser import get_data_available, parse_file
from discrete_optimization.rcpsp.problem import RcpspProblem
from discrete_optimization.rcpsp.solution import RcpspSolution
from discrete_optimization.rcpsp.solvers.cpsat import (
CpSatCumulativeResourceRcpspSolver,
CpSatRcpspSolver,
CpSatResourceRcpspSolver,
)
from discrete_optimization.rcpsp.solvers.cpsat_auto import (
CpSatAutoCumulativeResourceRcpspSolver,
CpSatAutoRcpspSolver,
)
from discrete_optimization.rcpsp.utils import plot_ressource_view, plot_task_gantt

logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)


def solve_makespan_with_cp_sat(problem: RcpspProblem):
solver = CpSatRcpspSolver(problem)
solver.init_model()
def solve_makespan_with_cp_sat(problem: RcpspProblem, auto: bool = True):
if auto:
solver = CpSatAutoRcpspSolver(problem)
solver.init_model(
use_cpm_for_task_bounds=True,
avoid_interval_optional=False,
use_energy_constraints=True,
)
else:
solver = CpSatRcpspSolver(problem)
solver.init_model()
parameters_cp = ParametersCp.default()
parameters_cp.nb_process = 8
result_storage = solver.solve(
Expand All @@ -45,8 +60,11 @@ def solve_makespan_with_cp_sat(problem: RcpspProblem):
)


def solve_resource_with_cp_sat(problem: RcpspProblem):
solver = CpSatCumulativeResourceRcpspSolver(problem)
def solve_resource_with_cp_sat(problem: RcpspProblem, auto: bool = True):
if auto:
solver = CpSatAutoCumulativeResourceRcpspSolver(problem)
else:
solver = CpSatCumulativeResourceRcpspSolver(problem)
solver.init_model(weight_on_used_resource=100, weight_on_makespan=1)
parameters_cp = ParametersCp.default()
parameters_cp.nb_process = 8
Expand All @@ -59,6 +77,7 @@ def solve_resource_with_cp_sat(problem: RcpspProblem):
time_limit=10,
)
# solution, fit = result_storage.get_best_solution_fit()
print([sol._internal_objectives for sol, _ in result_storage])
solution, fit = result_storage[-1]
plot_task_gantt(rcpsp_problem=problem, rcpsp_sol=solution, title="Resource optim")
plot_ressource_view(
Expand All @@ -77,9 +96,9 @@ def cpsat_single_mode_makespan_optimization():

def cpsat_single_mode_resource_optimization():
files_available = get_data_available()
file = [f for f in files_available if "j301_1.sm" in f][0]
file = [f for f in files_available if "j1201_1.sm" in f][0]
rcpsp_problem = parse_file(file)
solve_resource_with_cp_sat(rcpsp_problem)
solve_resource_with_cp_sat(rcpsp_problem, auto=True)


def cpsat_single_mode_makespan_optimization_rcp():
Expand Down Expand Up @@ -136,8 +155,46 @@ def cpsat_with_calendar():
print(solver.status_solver)


def run_multimode_rcpsp_resource():
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 = CpSatResourceRcpspSolver(problem=rcpsp_problem)
result_storage = solver.solve(time_limit=50)
solution, fit = result_storage.get_best_solution_fit()
plot_task_gantt(rcpsp_problem, solution)
plot_ressource_view(rcpsp_problem, solution)
solution: RcpspSolution
l = solution.check_non_renewable_resource_capacity_constraints(
resources=rcpsp_problem.non_renewable_resources_list
)
plt.show()
assert rcpsp_problem.satisfy(solution)
assert solution.check_all_calendar_resource_capacity_constraints()


def run_multimode_cumulative_rcpsp_resource():
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 = CpSatCumulativeResourceRcpspSolver(problem=rcpsp_problem)
result_storage = solver.solve(time_limit=50)
solution, fit = result_storage.get_best_solution_fit()
plot_task_gantt(rcpsp_problem, solution)
plot_ressource_view(rcpsp_problem, solution)
solution: RcpspSolution
l = solution.check_non_renewable_resource_capacity_constraints(
resources=rcpsp_problem.non_renewable_resources_list
)
plt.show()
assert rcpsp_problem.satisfy(solution)
assert solution.check_all_calendar_resource_capacity_constraints()


if __name__ == "__main__":
cpsat_single_mode_makespan_optimization()
cpsat_single_mode_resource_optimization()
plt.show()
# cpsat_single_mode_makespan_optimization()
# cpsat_single_mode_makespan_optimization()
# cpsat_single_mode_resource_optimization_rcp_sd()
# cpsat_single_mode_makespan_optimization()
Expand Down
106 changes: 106 additions & 0 deletions examples/rcpsp_resource_dependent/run_cpsat.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
# Copyright (c) 2026 AIRBUS and its affiliates.
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
from discrete_optimization.rcpsp_resource_dependent.problem import (
RcpspResourceDependentProblem,
RcpspResourceDependentSolution,
)
from discrete_optimization.rcpsp_resource_dependent.solvers.cpsat import (
CpSatRcpspResourceDependentSolver,
)


def create_toy_model():
resources = {"R1": 5, "R2": 8, "R3": 10, "N1": 20, "N2": 20}
mode_details = {
"source": {1: {"duration": 0}},
"1": {
1: {"R1": 1, "N1": 5, "duration": 2},
2: {"R2": 4, "N2": 5, "duration": 1},
},
"2": {
1: {
"R1": {frozenset([("1", 1)]): 1, frozenset([("1", 2)]): 5},
"N1": {frozenset([("1", 1)]): 20, frozenset([("1", 2)]): 10},
"duration": 2,
},
2: {
"R2": {frozenset([("1", 1)]): 1, frozenset([("1", 2)]): 5},
"N2": 5,
"duration": 1,
},
},
"3": {
1: {"R1": 1, "N1": 5, "duration": 3},
2: {"R2": 4, "N2": 5, "duration": 2},
},
"4": {
1: {"R1": 1, "N1": 5, "duration": 2},
2: {"R2": 4, "N2": 5, "duration": 3},
},
"5": {
1: {"R1": 1, "N1": 5, "duration": 4},
2: {"R2": 4, "N2": 5, "duration": 1},
},
"6": {
1: {"R1": 1, "N1": 5, "duration": 2},
2: {"R2": 4, "N2": 5, "duration": 1},
},
"sink": {1: {"duration": 0}},
}
successors = {
"source": ["1", "2"],
"1": ["3", "4"],
"2": ["5"],
"3": ["4"],
"4": ["6"],
"5": ["sink"],
"6": ["sink"],
"sink": [],
}
problem = RcpspResourceDependentProblem(
resources=resources,
non_renewable_resources=["N1", "N2"],
mode_details=mode_details,
successors=successors,
horizon=30,
source_task="source",
sink_task="sink",
)
solver = CpSatRcpspResourceDependentSolver(problem)
solver.init_model(avoid_interval_optional=False)
res = solver.solve(
time_limit=10, ortools_cpsat_solver_kwargs={"log_search_progress": True}
)
sol: RcpspResourceDependentSolution = res[-1][0]
resource_consumption = {}
total_conso_nr = {r: 0 for r in problem.non_renewable_resources}
for t in problem.tasks_list:
for r in problem.cumulative_resources_list:
resource_consumption[(t, r)] = sol.get_calendar_resource_consumption(r, t)
for r in problem.non_renewable_resources_list:
resource_consumption[(t, r)] = sol.get_non_renewable_resource_consumption(
r, t
)
total_conso_nr[r] += resource_consumption[(t, r)]
for t in problem.tasks_list:
for r in (
problem.cumulative_resources_list + problem.non_renewable_resources_list
):
print(t, r, ":", resource_consumption[(t, r)])
print(total_conso_nr)
print(sol.schedule, "\n", sol.modes)
print(problem.evaluate(sol), problem.satisfy(sol))
from discrete_optimization.generic_tasks_tools.plot_utils import (
plot_ressource_view,
plot_task_gantt,
plt,
)

plot_task_gantt(problem, sol)
plot_ressource_view(problem, sol)
plt.show()


if __name__ == "__main__":
create_toy_model()
8 changes: 8 additions & 0 deletions src/discrete_optimization/generic_tasks_tools/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Copyright (c) 2026 AIRBUS and its affiliates.
# This source code is licensed under the MIT license found in the
# LICENSE file in the root directory of this source tree.
from enum import Enum


class UndefinedInput(Enum):
UNDEFINED = 0
Loading