Skip to content

Commit

Permalink
Merge pull request #3251 from ZedongPeng/add_mindtpy_callback
Browse files Browse the repository at this point in the history
Add call_before_subproblem_solve callback in MindtPy
  • Loading branch information
blnicho authored May 8, 2024
2 parents a0765b4 + e4920cb commit ca3c34f
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 0 deletions.
13 changes: 13 additions & 0 deletions pyomo/contrib/mindtpy/algorithm_base_class.py
Original file line number Diff line number Diff line change
Expand Up @@ -2967,6 +2967,10 @@ def MindtPy_iteration_loop(self):
skip_fixed=False,
)
if self.curr_int_sol not in set(self.integer_list):
# Call the NLP pre-solve callback
with time_code(self.timing, 'Call before subproblem solve'):
config.call_before_subproblem_solve(self.fixed_nlp)

fixed_nlp, fixed_nlp_result = self.solve_subproblem()
self.handle_nlp_subproblem_tc(fixed_nlp, fixed_nlp_result)

Expand All @@ -2978,6 +2982,10 @@ def MindtPy_iteration_loop(self):
# Solve NLP subproblem
# The constraint linearization happens in the handlers
if not config.solution_pool:
# Call the NLP pre-solve callback
with time_code(self.timing, 'Call before subproblem solve'):
config.call_before_subproblem_solve(self.fixed_nlp)

fixed_nlp, fixed_nlp_result = self.solve_subproblem()
self.handle_nlp_subproblem_tc(fixed_nlp, fixed_nlp_result)

Expand Down Expand Up @@ -3010,6 +3018,11 @@ def MindtPy_iteration_loop(self):
continue
else:
self.integer_list.append(self.curr_int_sol)

# Call the NLP pre-solve callback
with time_code(self.timing, 'Call before subproblem solve'):
config.call_before_subproblem_solve(self.fixed_nlp)

fixed_nlp, fixed_nlp_result = self.solve_subproblem()
self.handle_nlp_subproblem_tc(fixed_nlp, fixed_nlp_result)

Expand Down
9 changes: 9 additions & 0 deletions pyomo/contrib/mindtpy/config_options.py
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,15 @@ def _add_common_configs(CONFIG):
doc='Callback hook after a solution of the main problem.',
),
)
CONFIG.declare(
'call_before_subproblem_solve',
ConfigValue(
default=_DoNothing(),
domain=None,
description='Function to be executed before every subproblem',
doc='Callback hook before a solution of the nonlinear subproblem.',
),
)
CONFIG.declare(
'call_after_subproblem_solve',
ConfigValue(
Expand Down
6 changes: 6 additions & 0 deletions pyomo/contrib/mindtpy/single_tree.py
Original file line number Diff line number Diff line change
Expand Up @@ -773,6 +773,9 @@ def __call__(self):
mindtpy_solver.integer_list.append(mindtpy_solver.curr_int_sol)

# solve subproblem
# Call the NLP pre-solve callback
with time_code(mindtpy_solver.timing, 'Call before subproblem solve'):
config.call_before_subproblem_solve(mindtpy_solver.fixed_nlp)
# The constraint linearization happens in the handlers
fixed_nlp, fixed_nlp_result = mindtpy_solver.solve_subproblem()
# add oa cuts
Expand Down Expand Up @@ -919,6 +922,9 @@ def LazyOACallback_gurobi(cb_m, cb_opt, cb_where, mindtpy_solver, config):
cut_ind = len(mindtpy_solver.mip.MindtPy_utils.cuts.oa_cuts)

# solve subproblem
# Call the NLP pre-solve callback
with time_code(mindtpy_solver.timing, 'Call before subproblem solve'):
config.call_before_subproblem_solve(mindtpy_solver.fixed_nlp)
# The constraint linearization happens in the handlers
fixed_nlp, fixed_nlp_result = mindtpy_solver.solve_subproblem()

Expand Down
24 changes: 24 additions & 0 deletions pyomo/contrib/mindtpy/tests/test_mindtpy.py
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,30 @@ def test_OA_rNLP(self):
)
self.check_optimal_solution(model)

def test_OA_callback(self):
"""Test the outer approximation decomposition algorithm."""
with SolverFactory('mindtpy') as opt:

def callback(model):
model.Y[1].value = 0
model.Y[2].value = 0
model.Y[3].value = 0

model = SimpleMINLP2()
# The callback function will make the OA method cycling.
results = opt.solve(
model,
strategy='OA',
init_strategy='rNLP',
mip_solver=required_solvers[1],
nlp_solver=required_solvers[0],
call_before_subproblem_solve=callback,
)
self.assertIs(
results.solver.termination_condition, TerminationCondition.feasible
)
self.assertAlmostEqual(value(results.problem.lower_bound), 5, places=1)

def test_OA_extreme_model(self):
"""Test the outer approximation decomposition algorithm."""
with SolverFactory('mindtpy') as opt:
Expand Down

0 comments on commit ca3c34f

Please sign in to comment.