Skip to content

Commit

Permalink
add sort_solutions method
Browse files Browse the repository at this point in the history
  • Loading branch information
ZedongPeng committed Jul 11, 2024
1 parent 9fd504a commit b6aa77d
Showing 1 changed file with 78 additions and 17 deletions.
95 changes: 78 additions & 17 deletions pyomo/contrib/mindtpy/algorithm_base_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -2974,7 +2974,7 @@ def MindtPy_iteration_loop(self):
fixed_nlp, fixed_nlp_result = self.solve_subproblem()
self.handle_nlp_subproblem_tc(fixed_nlp, fixed_nlp_result)

if self.algorithm_should_terminate(check_cycling=True):
if self.algorithm_should_terminate(check_cycling=not config.solution_pool):
self.last_iter_cuts = False
break

Expand All @@ -2998,26 +2998,31 @@ def MindtPy_iteration_loop(self):
break
else:
solution_name_obj = self.get_solution_name_obj(main_mip_results)
all_explored = True
for index, (name, _) in enumerate(solution_name_obj):
# the optimal solution of the main problem has been added to integer_list above
# so we should skip checking cycling for the first solution in the solution pool
if index > 0:
copy_var_list_values_from_solution_pool(
self.mip.MindtPy_utils.variable_list,
self.fixed_nlp.MindtPy_utils.variable_list,
config,
solver_model=main_mip_results._solver_model,
var_map=main_mip_results._pyomo_var_to_solver_var_map,
solution_name=name,
# self.algorithm_should_terminate(check_cycling=not config.solution_pool) has been changed.
# No longer need to skip cycling check for the best solution in the solution pool.
# if index > 0:

copy_var_list_values_from_solution_pool(
self.mip.MindtPy_utils.variable_list,
self.fixed_nlp.MindtPy_utils.variable_list,
config,
solver_model=main_mip_results._solver_model,
var_map=main_mip_results._pyomo_var_to_solver_var_map,
solution_name=name,
)
self.curr_int_sol = get_integer_solution(self.fixed_nlp)
if self.curr_int_sol in set(self.integer_list):
config.logger.info(
'The same combination has been explored and will be skipped here.'
)
self.curr_int_sol = get_integer_solution(self.fixed_nlp)
if self.curr_int_sol in set(self.integer_list):
config.logger.info(
'The same combination has been explored and will be skipped here.'
)
continue
else:
self.integer_list.append(self.curr_int_sol)
continue
else:
self.integer_list.append(self.curr_int_sol)
all_explored = False

# Call the NLP pre-solve callback
with time_code(self.timing, 'Call before subproblem solve'):
Expand All @@ -3033,6 +3038,11 @@ def MindtPy_iteration_loop(self):
if self.algorithm_should_terminate(check_cycling=False):
self.last_iter_cuts = True
break # TODO: break two loops.
if all_explored:
config.logger.info("Cycling")
if self.primal_bound not in [float('-inf'), float('inf')]:
self.results.solver.termination_condition = tc.feasible
break

# if add_no_good_cuts is True, the bound obtained in the last iteration is no reliable.
# we correct it after the iteration.
Expand All @@ -3049,6 +3059,18 @@ def MindtPy_iteration_loop(self):
)

def get_solution_name_obj(self, main_mip_results):
"""Obtain the name and objective value of the solutions in the solution pool.
Parameters
----------
main_mip_results : SolverResults
The results of the main problem.
Returns
-------
list
a 2D list containing the name and objective value of the solutions in the solution pool.
"""
if self.config.mip_solver == 'cplex_persistent':
solution_pool_names = (
main_mip_results._solver_model.solution.pool.get_names()
Expand All @@ -3067,13 +3089,52 @@ def get_solution_name_obj(self, main_mip_results):
gurobipy.GRB.Param.SolutionNumber, name
)
obj = main_mip_results._solver_model.PoolObjVal
# Here the list only contains the name and objective value of the solutions in the solution pool.
# If you want to add more information, you can add them here.
solution_name_obj.append([name, obj])
# sort the solutions by objective value, which can be changed according to the user's needs.
solution_name_obj.sort(
key=itemgetter(1), reverse=self.objective_sense == maximize
)
# TODO: I am not sure if you want to sort the solution pool or choose one solution from the pool.
# TODO: add whatever you want to sort the solution pool
self.sort_solutions(solution_name_obj, main_mip_results)
# only keep the first num_solution_iteration solutions
solution_name_obj = solution_name_obj[: self.config.num_solution_iteration]
return solution_name_obj

def sort_solutions(self, solution_name_obj, main_mip_results):
"""Choose the solutions from the solution pool.
Parameters
----------
solution_name_obj : list
a 2D list containing the name and objective value of the solutions in the solution pool.
main_mip_results : SolverResults
The results of the main problem.
Returns
-------
solution_name_obj : list
a sorted 2D list containing the name and objective value of the solutions in the solution pool.
"""
# Choose the solutions from the solution pool.
# for name, obj in solution_name_obj:
# # get the solution from the solution pool
# copy_var_list_values_from_solution_pool(
# self.mip.MindtPy_utils.variable_list,
# self.fixed_nlp.MindtPy_utils.variable_list,
# self.config,
# solver_model=main_mip_results._solver_model,
# var_map=main_mip_results._pyomo_var_to_solver_var_map,
# solution_name=name,
# )
# # Call your rl model or other strategies to sort the solution pools.

return solution_name_obj

def add_regularization(self):
if self.best_solution_found is not None:
# The main problem might be unbounded, regularization is activated only when a valid bound is provided.
Expand Down

0 comments on commit b6aa77d

Please sign in to comment.