Skip to content

Commit

Permalink
Remove limit on nb of solutions in parameters for milp and cp
Browse files Browse the repository at this point in the history
  • Loading branch information
nhuet committed Sep 19, 2024
1 parent e78275b commit f3b0078
Show file tree
Hide file tree
Showing 14 changed files with 26 additions and 61 deletions.
18 changes: 0 additions & 18 deletions discrete_optimization/generic_tools/cp_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -87,8 +87,6 @@ class ParametersCP:
"""

intermediate_solution: bool
all_solutions: bool
nr_solutions: int
free_search: bool
multiprocess: bool
nb_process: int
Expand All @@ -97,8 +95,6 @@ class ParametersCP:
def __init__(
self,
intermediate_solution: bool,
all_solutions: bool,
nr_solutions: int,
free_search: bool = False,
multiprocess: bool = False,
nb_process: int = 1,
Expand All @@ -107,12 +103,8 @@ def __init__(
"""
:param intermediate_solution: retrieve intermediate solutions
:param all_solutions: returns all solutions found by the cp solver
:param nr_solutions: the requested number of solutions
"""
self.intermediate_solution = intermediate_solution
self.all_solutions = all_solutions
self.nr_solutions = nr_solutions
self.free_search = free_search
self.multiprocess = multiprocess
self.nb_process = nb_process
Expand All @@ -122,8 +114,6 @@ def __init__(
def default() -> "ParametersCP":
return ParametersCP(
intermediate_solution=True,
all_solutions=False,
nr_solutions=1000,
free_search=False,
optimisation_level=1,
)
Expand All @@ -132,8 +122,6 @@ def default() -> "ParametersCP":
def default_cpsat() -> "ParametersCP":
return ParametersCP(
intermediate_solution=True,
all_solutions=False,
nr_solutions=1000,
free_search=False,
multiprocess=True,
nb_process=6,
Expand All @@ -144,25 +132,19 @@ def default_cpsat() -> "ParametersCP":
def default_fast_lns() -> "ParametersCP":
return ParametersCP(
intermediate_solution=True,
all_solutions=False,
nr_solutions=1000,
free_search=False,
)

@staticmethod
def default_free() -> "ParametersCP":
return ParametersCP(
intermediate_solution=True,
all_solutions=False,
nr_solutions=1000,
free_search=True,
)

def copy(self) -> "ParametersCP":
return ParametersCP(
intermediate_solution=self.intermediate_solution,
all_solutions=self.all_solutions,
nr_solutions=self.nr_solutions,
free_search=self.free_search,
multiprocess=self.multiprocess,
nb_process=self.nb_process,
Expand Down
8 changes: 2 additions & 6 deletions discrete_optimization/generic_tools/lp_tools.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,14 +63,12 @@ def __init__(
mip_gap_abs: float,
mip_gap: float,
retrieve_all_solution: bool,
n_solutions_max: int,
pool_search_mode: int = 0,
):
self.pool_solutions = pool_solutions
self.mip_gap_abs = mip_gap_abs
self.mip_gap = mip_gap
self.retrieve_all_solution = retrieve_all_solution
self.n_solutions_max = n_solutions_max
self.pool_search_mode = pool_search_mode

@staticmethod
Expand All @@ -80,7 +78,6 @@ def default() -> "ParametersMilp":
mip_gap_abs=0.0000001,
mip_gap=0.000001,
retrieve_all_solution=True,
n_solutions_max=10000,
)


Expand All @@ -101,7 +98,7 @@ def retrieve_solutions(self, parameters_milp: ParametersMilp) -> ResultStorage:
"""
if parameters_milp.retrieve_all_solution:
n_solutions = min(parameters_milp.n_solutions_max, self.nb_solutions)
n_solutions = self.nb_solutions
else:
n_solutions = 1
list_solution_fits: List[Tuple[Solution, Union[float, TupleFitness]]] = []
Expand Down Expand Up @@ -238,7 +235,6 @@ def prepare_model(
self.model.sol_pool_size = parameters_milp.pool_solutions
if time_limit is not None:
self.model.max_seconds = time_limit
self.model.max_solutions = parameters_milp.n_solutions_max

def optimize_model(
self,
Expand Down Expand Up @@ -475,7 +471,7 @@ def solve(
self.model.time_limit = time_limit
self.model.parameters.mip.tolerances.mipgap = parameters_milp.mip_gap
listener = None
if parameters_milp.retrieve_all_solution or parameters_milp.n_solutions_max > 1:
if parameters_milp.retrieve_all_solution:

class SolutionStorage(SolutionListener):
def __init__(self):
Expand Down
10 changes: 6 additions & 4 deletions discrete_optimization/rcpsp/solver/cp_solvers.py
Original file line number Diff line number Diff line change
Expand Up @@ -1842,6 +1842,8 @@ def solve(
self,
parameters_cp: Optional[ParametersCP] = None,
time_limit: Optional[float] = 100.0,
nr_solutions: int = 1,
all_solutions: bool = False,
**args,
):
"""Solve the CP problem with minizinc
Expand All @@ -1850,6 +1852,8 @@ def solve(
parameters_cp: parameters specific to CP solvers
time_limit: the solve process stops after this time limit (in seconds).
If None, no time limit is applied.
nr_solutions: of not `all_solutions`, the solve stops after finding `nr_solutions`
all_solutions: if True, do not stop when reaching `nr_solutions`
**args: passed to init_model()
Returns:
Expand All @@ -1866,10 +1870,8 @@ def solve(
timeout = timedelta(seconds=time_limit)
result = self.instance.solve(
timeout=timeout,
nr_solutions=parameters_cp.nr_solutions
if not parameters_cp.all_solutions
else None,
all_solutions=parameters_cp.all_solutions,
nr_solutions=nr_solutions if not all_solutions else None,
all_solutions=all_solutions,
intermediate_solutions=intermediate_solutions,
)
logger.debug(result.status)
Expand Down
1 change: 0 additions & 1 deletion discrete_optimization/rcpsp/solver/rcpsp_lp_lns_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -430,7 +430,6 @@ def __init__(
mip_gap_abs=0.001,
mip_gap=0.001,
retrieve_all_solution=True,
n_solutions_max=100,
)
self.constraint_handler = ConstraintHandlerStartTimeIntervalMRCPSP(
problem=problem, fraction_to_fix=0.6, minus_delta=5, plus_delta=5
Expand Down
14 changes: 6 additions & 8 deletions discrete_optimization/rcpsp/solver/rcpsp_pile.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,10 +83,9 @@ def __init__(
}
if problem.is_rcpsp_multimode() or problem.is_varying_resource():
solver = CP_MRCPSP_MZN_MODES(problem, cp_solver_name=CPSolverName.CHUFFED)
params_cp = ParametersCP.default()
params_cp.nr_solutions = 1
params_cp.all_solutions = False
result_storage = solver.solve(parameters_cp=params_cp, time_limit=1)
result_storage = solver.solve(
nr_solutions=1, all_solutions=False, time_limit=1
)
one_mode_setting = result_storage[0]
self.modes_dict = {}
for i in range(len(one_mode_setting)):
Expand Down Expand Up @@ -285,10 +284,9 @@ def __init__(
}
if problem.is_rcpsp_multimode() or problem.is_varying_resource():
solver = CP_MRCPSP_MZN_MODES(problem, cp_solver_name=CPSolverName.CHUFFED)
params_cp = ParametersCP.default()
params_cp.nr_solutions = 1
params_cp.all_solutions = False
result_storage = solver.solve(parameters_cp=params_cp, time_limit=1)
result_storage = solver.solve(
nr_solutions=1, all_solutions=False, time_limit=1
)
one_mode_setting = result_storage[0]
self.modes_dict = {}
for i in range(len(one_mode_setting)):
Expand Down
9 changes: 4 additions & 5 deletions discrete_optimization/rcpsp_multiskill/multiskill_to_rcpsp.py
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,8 @@ def construct_rcpsp_by_worker_type(
check_resource_compliance: bool = True,
one_worker_type_per_task: bool = False,
):
params_cp = ParametersCP(
intermediate_solution=True,
all_solutions=False,
nr_solutions=100,
)
params_cp = ParametersCP.default()
params_cp.intermediate_solution = True
solver = PrecomputeEmployeesForTasks(
ms_rcpsp_model=self.multiskill_model, cp_solver_name=CPSolverName.CHUFFED
)
Expand Down Expand Up @@ -96,6 +93,8 @@ def construct_rcpsp_by_worker_type(
results = solver.solve(
parameters_cp=params_cp,
time_limit=30,
all_solutions=False,
nr_solutions=100,
)
best_overskill_results = min(
results, key=lambda x: x.overskill_type
Expand Down
7 changes: 6 additions & 1 deletion discrete_optimization/rcpsp_multiskill/solvers/cp_solvers.py
Original file line number Diff line number Diff line change
Expand Up @@ -2213,6 +2213,8 @@ def solve(
self,
parameters_cp: Optional[ParametersCP] = None,
time_limit: Optional[float] = 100.0,
nr_solutions: int = 100,
all_solutions: bool = False,
**args,
):
"""Solve the CP problem with minizinc
Expand All @@ -2221,6 +2223,8 @@ def solve(
parameters_cp: parameters specific to CP solvers
time_limit: the solve process stops after this time limit (in seconds).
If None, no time limit is applied.
nr_solutions: of not `all_solutions`, the solve stops after finding `nr_solutions`
all_solutions: if True, do not stop when reaching `nr_solutions`
**args: passed to init_model()
Returns:
Expand All @@ -2237,8 +2241,9 @@ def solve(
timeout = timedelta(seconds=time_limit)
result = self.instance.solve(
timeout=timeout,
nr_solutions=parameters_cp.nr_solutions,
intermediate_solutions=intermediate_solutions,
nr_solutions=nr_solutions,
all_solutions=all_solutions,
)
logger.debug(result.status)
return self.retrieve_solutions(result=result, parameters_cp=parameters_cp)
2 changes: 0 additions & 2 deletions examples/rcpsp/rcpsp_cpsat_solver_example.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ def solve_makespan_with_cp_sat(problem: RCPSPModel):
solver = CPSatRCPSPSolver(problem)
solver.init_model()
parameters_cp = ParametersCP.default()
parameters_cp.nr_solutions = 1
parameters_cp.nb_process = 8
result_storage = solver.solve(
callbacks=[
Expand All @@ -51,7 +50,6 @@ def solve_resource_with_cp_sat(problem: RCPSPModel):
solver = CPSatRCPSPSolverCumulativeResource(problem)
solver.init_model(weight_on_used_resource=100, weight_on_makespan=1)
parameters_cp = ParametersCP.default()
parameters_cp.nr_solutions = 1
parameters_cp.nb_process = 8
result_storage = solver.solve(
callbacks=[
Expand Down
1 change: 0 additions & 1 deletion tests/facility/test_facility_lp_lns.py
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,6 @@ def test_facility_lns():
mip_gap=0.0001,
mip_gap_abs=0.001,
retrieve_all_solution=True,
n_solutions_max=1000,
)
solver = LP_Facility_Solver_PyMip(
facility_problem,
Expand Down
1 change: 0 additions & 1 deletion tests/knapsack/test_knapsack_lp_lns_solver.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ def test_knapsack_lns():
mip_gap=0.0001,
mip_gap_abs=0.001,
retrieve_all_solution=True,
n_solutions_max=1000,
)
solver = LPKnapsack(
model,
Expand Down
8 changes: 1 addition & 7 deletions tests/rcpsp/solver/test_rcpsp_cp.py
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,6 @@ def test_cp_sm(optimisation_level):
solver = CP_RCPSP_MZN(rcpsp_problem, cp_solver_name=CPSolverName.CHUFFED)
solver.init_model(output_type=True)
parameters_cp = ParametersCP.default()
parameters_cp.nr_solutions = 1
parameters_cp.optimisation_level = optimisation_level
result_storage = solver.solve(parameters_cp=parameters_cp, time_limit=100)
solution, fit = result_storage.get_best_solution_fit()
Expand Down Expand Up @@ -104,7 +103,6 @@ def test_cp_rcp(optimisation_level):
solver = CP_RCPSP_MZN(rcpsp_problem, cp_solver_name=CPSolverName.CHUFFED)
solver.init_model(output_type=True)
parameters_cp = ParametersCP.default()
parameters_cp.nr_solutions = 1
parameters_cp.optimisation_level = optimisation_level
result_storage = solver.solve(parameters_cp=parameters_cp, time_limit=20)
solution, fit = result_storage.get_best_solution_fit()
Expand Down Expand Up @@ -192,8 +190,6 @@ def test_ortools_with_cb(caplog, random_seed):
file = [f for f in files_available if model in f][0]
rcpsp_problem = parse_file(file)
solver = CPSatRCPSPSolver(problem=rcpsp_problem)
parameters_cp = ParametersCP.default()
parameters_cp.nr_solutions = 1

class VariablePrinterCallback(Callback):
def __init__(self) -> None:
Expand All @@ -211,9 +207,7 @@ def on_step_end(self, step: int, res: ResultStorage, solver: CPSatRCPSPSolver):
callbacks = [VariablePrinterCallback(), TimerStopper(2)]

with caplog.at_level(logging.DEBUG):
result_storage = solver.solve(
callbacks=callbacks, parameters_cp=parameters_cp, time_limit=10
)
result_storage = solver.solve(callbacks=callbacks, time_limit=10)

assert "Solution #1" in caplog.text
assert (
Expand Down
5 changes: 1 addition & 4 deletions tests/rcpsp/solver/test_rcpsp_find_modes.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,7 @@ def test_find_modes():
file = [f for f in files_available if "j1010_1.mm" in f][0]
rcpsp_problem = parse_file(file)
solver = CP_MRCPSP_MZN_MODES(rcpsp_problem, cp_solver_name=CPSolverName.CHUFFED)
params_cp = ParametersCP.default()
params_cp.nr_solutions = float("inf")
params_cp.all_solutions = True
result_storage = solver.solve(parameters_cp=params_cp)
result_storage = solver.solve(all_solutions=True)
assert len(result_storage) == 12744


Expand Down
2 changes: 0 additions & 2 deletions tests/rcpsp/solver/test_rcpsp_lp_lns.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,6 @@ def test_lns_sm():
mip_gap_abs=0.001,
mip_gap=0.001,
retrieve_all_solution=True,
n_solutions_max=100,
)
params_objective_function = get_default_objective_setup(problem=rcpsp_problem)
constraint_handler = ConstraintHandlerStartTimeInterval(
Expand Down Expand Up @@ -105,7 +104,6 @@ def test_lns_mm():
mip_gap_abs=0.001,
mip_gap=0.001,
retrieve_all_solution=True,
n_solutions_max=100,
)
constraint_handler = ConstraintHandlerFixStartTime(
problem=rcpsp_problem, fraction_fix_start_time=0.3
Expand Down
1 change: 0 additions & 1 deletion tests/rcpsp_multiskill/test_rcpsp_ms_lp_lns.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,6 @@ def test_multiskill_imopse():
mip_gap_abs=0.001,
mip_gap=0.001,
retrieve_all_solution=True,
n_solutions_max=100,
)
constraint_handler = ConstraintHandlerStartTimeIntervalMRCPSP(
problem=model, fraction_to_fix=0.95, minus_delta=5, plus_delta=5
Expand Down

0 comments on commit f3b0078

Please sign in to comment.