def handle_lazy_subproblem_optimal(self, fixed_nlp, solve_data, config, opt): """This function copies the optimal solution of the fixed NLP subproblem to the MIP main problem(explanation see below), updates bound, adds OA and no-good cuts, stores incumbent solution if it has been improved. Parameters ---------- fixed_nlp : Pyomo model Integer-variable-fixed NLP model. solve_data : MindtPySolveData Data container that holds solve-instance data. config : ConfigBlock The specific configurations for MindtPy. opt : SolverFactory The cplex_persistent solver. """ if config.calculate_dual: for c in fixed_nlp.tmp_duals: if fixed_nlp.dual.get(c, None) is None: fixed_nlp.dual[c] = fixed_nlp.tmp_duals[c] dual_values = list( fixed_nlp.dual[c] for c in fixed_nlp.MindtPy_utils.constraint_list) else: dual_values = None main_objective = fixed_nlp.MindtPy_utils.objective_list[-1] update_primal_bound(solve_data, value(main_objective.expr)) if solve_data.primal_bound_improved: solve_data.best_solution_found = fixed_nlp.clone() solve_data.best_solution_found_time = get_main_elapsed_time( solve_data.timing) if config.add_no_good_cuts or config.use_tabu_list: solve_data.stored_bound.update( {solve_data.primal_bound: solve_data.dual_bound}) config.logger.info( solve_data.fixed_nlp_log_formatter.format( '*' if solve_data.primal_bound_improved else ' ', solve_data.nlp_iter, 'Fixed NLP', value(main_objective.expr), solve_data.primal_bound, solve_data.dual_bound, solve_data.rel_gap, get_main_elapsed_time(solve_data.timing))) # In OA algorithm, OA cuts are generated based on the solution of the subproblem # We need to first copy the value of variables from the subproblem and then add cuts # since value(constr.body), value(jacs[constr][var]), value(var) are used in self.add_lazy_oa_cuts() copy_var_list_values(fixed_nlp.MindtPy_utils.variable_list, solve_data.mip.MindtPy_utils.variable_list, config) if config.strategy == 'OA': self.add_lazy_oa_cuts(solve_data.mip, dual_values, solve_data, config, opt) if config.add_regularization is not None: add_oa_cuts(solve_data.mip, dual_values, solve_data, config) elif config.strategy == 'GOA': self.add_lazy_affine_cuts(solve_data, config, opt) if config.add_no_good_cuts: var_values = list(v.value for v in fixed_nlp.MindtPy_utils.variable_list) self.add_lazy_no_good_cuts(var_values, solve_data, config, opt)
def handle_subproblem_optimal(fixed_nlp, solve_data, config, cb_opt=None, fp=False): """This function copies the result of the NLP solver function ('solve_subproblem') to the working model, updates the bounds, adds OA and no-good cuts, and then stores the new solution if it is the new best solution. This function handles the result of the latest iteration of solving the NLP subproblem given an optimal solution. Parameters ---------- fixed_nlp : Pyomo model Integer-variable-fixed NLP model. solve_data : MindtPySolveData Data container that holds solve-instance data. config : ConfigBlock The specific configurations for MindtPy. cb_opt : SolverFactory, optional The gurobi_persistent solver, by default None. fp : bool, optional Whether it is in the loop of feasibility pump, by default False. """ copy_var_list_values(fixed_nlp.MindtPy_utils.variable_list, solve_data.working_model.MindtPy_utils.variable_list, config) if config.calculate_dual: for c in fixed_nlp.tmp_duals: if fixed_nlp.dual.get(c, None) is None: fixed_nlp.dual[c] = fixed_nlp.tmp_duals[c] dual_values = list(fixed_nlp.dual[c] for c in fixed_nlp.MindtPy_utils.constraint_list) else: dual_values = None main_objective = fixed_nlp.MindtPy_utils.objective_list[-1] update_primal_bound(solve_data, value(main_objective.expr)) if solve_data.primal_bound_improved: solve_data.best_solution_found = fixed_nlp.clone() solve_data.best_solution_found_time = get_main_elapsed_time( solve_data.timing) if config.strategy == 'GOA': solve_data.num_no_good_cuts_added.update({ solve_data.primal_bound: len(solve_data.mip.MindtPy_utils.cuts.no_good_cuts) }) # add obj increasing constraint for fp if fp: solve_data.mip.MindtPy_utils.cuts.del_component( 'improving_objective_cut') if solve_data.objective_sense == minimize: solve_data.mip.MindtPy_utils.cuts.improving_objective_cut = Constraint( expr=sum(solve_data.mip.MindtPy_utils.objective_value[:]) <= solve_data.primal_bound - config.fp_cutoffdecr * max(1, abs(solve_data.primal_bound))) else: solve_data.mip.MindtPy_utils.cuts.improving_objective_cut = Constraint( expr=sum(solve_data.mip.MindtPy_utils.objective_value[:]) >= solve_data.primal_bound + config.fp_cutoffdecr * max(1, abs(solve_data.primal_bound))) # Add the linear cut if config.strategy == 'OA' or fp: copy_var_list_values(fixed_nlp.MindtPy_utils.variable_list, solve_data.mip.MindtPy_utils.variable_list, config) add_oa_cuts(solve_data.mip, dual_values, solve_data, config, cb_opt) elif config.strategy == 'GOA': copy_var_list_values(fixed_nlp.MindtPy_utils.variable_list, solve_data.mip.MindtPy_utils.variable_list, config) add_affine_cuts(solve_data, config) # elif config.strategy == 'PSC': # # !!THIS SEEMS LIKE A BUG!! - mrmundt # # add_psc_cut(solve_data, config) # elif config.strategy == 'GBD': # # !!THIS SEEMS LIKE A BUG!! - mrmundt # # add_gbd_cut(solve_data, config) var_values = list(v.value for v in fixed_nlp.MindtPy_utils.variable_list) if config.add_no_good_cuts: add_no_good_cuts(var_values, solve_data, config) config.call_after_subproblem_feasible(fixed_nlp, solve_data) config.logger.info( solve_data.fixed_nlp_log_formatter.format( '*' if solve_data.primal_bound_improved else ' ', solve_data.nlp_iter if not fp else solve_data.fp_iter, 'Fixed NLP', value(main_objective.expr), solve_data.primal_bound, solve_data.dual_bound, solve_data.rel_gap, get_main_elapsed_time(solve_data.timing)))