Skip to content

Commit

Permalink
temp
Browse files Browse the repository at this point in the history
  • Loading branch information
ZedongPeng committed Jun 17, 2023
1 parent 596ddb7 commit cecc51b
Show file tree
Hide file tree
Showing 5 changed files with 81 additions and 72 deletions.
10 changes: 6 additions & 4 deletions pyomo/contrib/mindtpy/algorithm_base_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -1608,8 +1608,9 @@ def set_up_lazy_OA_callback(self):
if self.config.mip_solver == 'gurobi_persistent':
self.mip_opt.set_callback(single_tree.LazyOACallback_gurobi)
self.solve_data = MindtPySolveData()
self.export_attributes()
self.mip_opt.solve_data = self.solve_data
# self.export_attributes()
self.mip_opt.mindtpy_object = self
# self.mip_opt.solve_data = self.solve_data
self.mip_opt.config = self.config

##########################################################################################################################################
Expand Down Expand Up @@ -1641,8 +1642,8 @@ def solve_main(self, config):
self.mip, tee=config.mip_solver_tee, load_solutions=False, **mip_args
)
# update_attributes should be before load_from(main_mip_results), since load_from(main_mip_results) may fail.
if config.single_tree or config.use_tabu_list:
self.update_attributes()
# if config.single_tree or config.use_tabu_list:
# self.update_attributes()
if len(main_mip_results.solution) > 0:
self.mip.solutions.load_from(main_mip_results)
except (ValueError, AttributeError, RuntimeError):
Expand Down Expand Up @@ -2692,6 +2693,7 @@ def initialize_subsolvers(self):
"""Initialize and set options for MIP and NLP subsolvers."""
config = self.config
if config.mip_solver == 'gurobi_persistent' and config.single_tree:
print('2----------------')
self.mip_opt = GurobiPersistent4MindtPy()
else:
self.mip_opt = SolverFactory(config.mip_solver)
Expand Down
2 changes: 2 additions & 0 deletions pyomo/contrib/mindtpy/mip_solve.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,8 +183,10 @@ def set_up_mip_solver(solve_data, config, regularization_problem):
mainopt = SolverFactory(config.mip_regularization_solver)
else:
if config.mip_solver == 'gurobi_persistent' and config.single_tree:
print('1~~~~~~~~~~~~~~~~')
mainopt = GurobiPersistent4MindtPy()
mainopt.solve_data = solve_data
# mainopt.mindtpy_object = self
mainopt.config = config
else:
mainopt = SolverFactory(config.mip_solver)
Expand Down
90 changes: 47 additions & 43 deletions pyomo/contrib/mindtpy/single_tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -906,7 +906,7 @@ def __call__(self):
# Gurobi


def LazyOACallback_gurobi(cb_m, cb_opt, cb_where, solve_data, config):
def LazyOACallback_gurobi(cb_m, cb_opt, cb_where, mindtpy_object, config):
"""This is a GUROBI callback function defined for LP/NLP based B&B algorithm.
Parameters
Expand All @@ -917,114 +917,117 @@ def LazyOACallback_gurobi(cb_m, cb_opt, cb_where, solve_data, config):
The gurobi_persistent solver.
cb_where : int
An enum member of gurobipy.GRB.Callback.
solve_data : MindtPySolveData
mindtpy_object : MindtPySolveData
Data container that holds solve-instance data.
config : ConfigBlock
The specific configurations for MindtPy.
"""
if cb_where == gurobipy.GRB.Callback.MIPSOL:
# gurobipy.GRB.Callback.MIPSOL means that an integer solution is found during the branch and bound process
if solve_data.should_terminate:
if mindtpy_object.should_terminate:
cb_opt._solver_model.terminate()
return
cb_opt.cbGetSolution(vars=cb_m.MindtPy_utils.variable_list)
handle_lazy_main_feasible_solution_gurobi(cb_m, cb_opt, solve_data, config)
handle_lazy_main_feasible_solution_gurobi(cb_m, cb_opt, mindtpy_object, config)

if config.add_cuts_at_incumbent:
if config.strategy == 'OA':
add_oa_cuts(
solve_data.mip,
mindtpy_object.mip,
None,
solve_data.jacobians,
solve_data.objective_sense,
solve_data.mip_constraint_polynomial_degree,
solve_data.mip_iter,
mindtpy_object.jacobians,
mindtpy_object.objective_sense,
mindtpy_object.mip_constraint_polynomial_degree,
mindtpy_object.mip_iter,
config,
solve_data.timing,
mindtpy_object.timing,
cb_opt=cb_opt,
)

# Regularization is activated after the first feasible solution is found.
if (
config.add_regularization is not None
and solve_data.best_solution_found is not None
and mindtpy_object.best_solution_found is not None
):
# The main problem might be unbounded, regularization is activated only when a valid bound is provided.
if (
not solve_data.dual_bound_improved
and not solve_data.primal_bound_improved
not mindtpy_object.dual_bound_improved
and not mindtpy_object.primal_bound_improved
):
config.logger.debug(
'The bound and the best found solution have neither been improved.'
'We will skip solving the regularization problem and the Fixed-NLP subproblem'
)
solve_data.primal_bound_improved = False
mindtpy_object.primal_bound_improved = False
return
if solve_data.dual_bound != solve_data.dual_bound_progress[0]:
if mindtpy_object.dual_bound != mindtpy_object.dual_bound_progress[0]:
main_mip, main_mip_results = solve_main(
solve_data, config, regularization_problem=True
mindtpy_object, config, regularization_problem=True
)
handle_regularization_main_tc(
main_mip, main_mip_results, solve_data, config
# handle_regularization_main_tc(
# main_mip, main_mip_results, mindtpy_object, config
# )
mindtpy_object.handle_regularization_main_tc(
main_mip, main_mip_results, config
)

if (
abs(solve_data.primal_bound - solve_data.dual_bound)
abs(mindtpy_object.primal_bound - mindtpy_object.dual_bound)
<= config.absolute_bound_tolerance
):
config.logger.info(
'MindtPy exiting on bound convergence. '
'|Primal Bound: {} - Dual Bound: {}| <= (absolute tolerance {}) \n'.format(
solve_data.primal_bound,
solve_data.dual_bound,
mindtpy_object.primal_bound,
mindtpy_object.dual_bound,
config.absolute_bound_tolerance,
)
)
solve_data.results.solver.termination_condition = tc.optimal
mindtpy_object.results.solver.termination_condition = tc.optimal
cb_opt._solver_model.terminate()
return

# # check if the same integer combination is obtained.
solve_data.curr_int_sol = get_integer_solution(
solve_data.working_model, string_zero=True
mindtpy_object.curr_int_sol = get_integer_solution(
mindtpy_object.working_model, string_zero=True
)

if solve_data.curr_int_sol in set(solve_data.integer_list):
if mindtpy_object.curr_int_sol in set(mindtpy_object.integer_list):
config.logger.debug(
'This integer combination has been explored. '
'We will skip solving the Fixed-NLP subproblem.'
)
solve_data.primal_bound_improved = False
mindtpy_object.primal_bound_improved = False
if config.strategy == 'GOA':
if config.add_no_good_cuts:
var_values = list(
v.value
for v in solve_data.working_model.MindtPy_utils.variable_list
for v in mindtpy_object.working_model.MindtPy_utils.variable_list
)
add_no_good_cuts(
solve_data.mip,
mindtpy_object.mip,
var_values,
config,
solve_data.timing,
mip_iter=solve_data.mip_iter,
mindtpy_object.timing,
mip_iter=mindtpy_object.mip_iter,
cb_opt=cb_opt,
)
return
elif config.strategy == 'OA':
return
else:
solve_data.integer_list.append(solve_data.curr_int_sol)
mindtpy_object.integer_list.append(mindtpy_object.curr_int_sol)

# solve subproblem
# The constraint linearization happens in the handlers
fixed_nlp, fixed_nlp_result = solve_subproblem(solve_data, config)
fixed_nlp, fixed_nlp_result = solve_subproblem(mindtpy_object, config)

handle_nlp_subproblem_tc(
fixed_nlp, fixed_nlp_result, solve_data, config, cb_opt
fixed_nlp, fixed_nlp_result, mindtpy_object, config, cb_opt
)


def handle_lazy_main_feasible_solution_gurobi(cb_m, cb_opt, solve_data, config):
def handle_lazy_main_feasible_solution_gurobi(cb_m, cb_opt, mindtpy_object, config):
"""This function is called during the branch and bound of main MIP problem,
more exactly when a feasible solution is found and LazyCallback is activated.
Expand All @@ -1037,7 +1040,7 @@ def handle_lazy_main_feasible_solution_gurobi(cb_m, cb_opt, solve_data, config):
The MIP main problem.
cb_opt : SolverFactory
The gurobi_persistent solver.
solve_data : MindtPySolveData
mindtpy_object : MindtPySolveData
Data container that holds solve-instance data.
config : ConfigBlock
The specific configurations for MindtPy.
Expand All @@ -1047,18 +1050,19 @@ def handle_lazy_main_feasible_solution_gurobi(cb_m, cb_opt, solve_data, config):
# this value copy is useful since we need to fix subproblem based on the solution of the main problem
copy_var_list_values(
cb_m.MindtPy_utils.variable_list,
solve_data.working_model.MindtPy_utils.variable_list,
mindtpy_object.working_model.MindtPy_utils.variable_list,
config,
)
update_dual_bound(solve_data, cb_opt.cbGet(gurobipy.GRB.Callback.MIPSOL_OBJBND))
mindtpy_object.update_dual_bound(cb_opt.cbGet(gurobipy.GRB.Callback.MIPSOL_OBJBND))
# update_dual_bound(solve_data, cb_opt.cbGet(gurobipy.GRB.Callback.MIPSOL_OBJBND))
config.logger.info(
solve_data.log_formatter.format(
solve_data.mip_iter,
mindtpy_object.log_formatter.format(
mindtpy_object.mip_iter,
'restrLP',
cb_opt.cbGet(gurobipy.GRB.Callback.MIPSOL_OBJ),
solve_data.primal_bound,
solve_data.dual_bound,
solve_data.rel_gap,
get_main_elapsed_time(solve_data.timing),
mindtpy_object.primal_bound,
mindtpy_object.dual_bound,
mindtpy_object.rel_gap,
get_main_elapsed_time(mindtpy_object.timing),
)
)
49 changes: 25 additions & 24 deletions pyomo/contrib/mindtpy/tests/test_mindtpy_lp_nlp.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@
from pyomo.opt import TerminationCondition

required_nlp_solvers = 'ipopt'
required_mip_solvers = ['cplex_persistent', 'gurobi_persistent']
required_mip_solvers = ['gurobi_persistent']
# required_mip_solvers = ['cplex_persistent', 'gurobi_persistent']
available_mip_solvers = [
s for s in required_mip_solvers if SolverFactory(s).available(False)
]
Expand Down Expand Up @@ -68,30 +69,30 @@ def check_optimal_solution(self, model, places=1):
var.value, model.optimal_solution[var], places=places
)

@unittest.skipUnless(
'cplex_persistent' in available_mip_solvers,
'cplex_persistent solver is not available',
)
def test_LPNLP_CPLEX(self):
"""Test the LP/NLP decomposition algorithm."""
with SolverFactory('mindtpy') as opt:
for model in model_list:
results = opt.solve(
model,
strategy='OA',
mip_solver='cplex_persistent',
nlp_solver=required_nlp_solvers,
single_tree=True,
)
# @unittest.skipUnless(
# 'cplex_persistent' in available_mip_solvers,
# 'cplex_persistent solver is not available',
# )
# def test_LPNLP_CPLEX(self):
# """Test the LP/NLP decomposition algorithm."""
# with SolverFactory('mindtpy') as opt:
# for model in model_list:
# results = opt.solve(
# model,
# strategy='OA',
# mip_solver='cplex_persistent',
# nlp_solver=required_nlp_solvers,
# single_tree=True,
# )

self.assertIn(
results.solver.termination_condition,
[TerminationCondition.optimal, TerminationCondition.feasible],
)
self.assertAlmostEqual(
value(model.objective.expr), model.optimal_value, places=1
)
self.check_optimal_solution(model)
# self.assertIn(
# results.solver.termination_condition,
# [TerminationCondition.optimal, TerminationCondition.feasible],
# )
# self.assertAlmostEqual(
# value(model.objective.expr), model.optimal_value, places=1
# )
# self.check_optimal_solution(model)

@unittest.skipUnless(
'gurobi_persistent' in available_mip_solvers,
Expand Down
2 changes: 1 addition & 1 deletion pyomo/contrib/mindtpy/util.py
Original file line number Diff line number Diff line change
Expand Up @@ -874,7 +874,7 @@ def f(gurobi_model, where):
where (int): an enum member of gurobipy.GRB.Callback.
"""
self._callback_func(
self._pyomo_model, self, where, self.solve_data, self.config
self._pyomo_model, self, where, self.mindtpy_object, self.config
)

return f
Expand Down

0 comments on commit cecc51b

Please sign in to comment.