Ejemplo n.º 1
0
def handle_main_max_timelimit(main_mip, main_mip_results, solve_data, config):
    """This function handles the result of the latest iteration of solving the MIP problem
    given that solving the MIP takes too long.

    Parameters
    ----------
    main_mip : Pyomo model
        The MIP main problem.
    main_mip_results : [type]
        Results from solving the MIP main subproblem.
    solve_data : MindtPySolveData
        Data container that holds solve-instance data.
    config : ConfigBlock
        The specific configurations for MindtPy.
    """
    # TODO if we have found a valid feasible solution, we take that, if not, we can at least use the dual bound
    MindtPy = main_mip.MindtPy_utils
    config.logger.info('Unable to optimize MILP main problem '
                       'within time limit. '
                       'Using current solver feasible solution.')
    copy_var_list_values(main_mip.MindtPy_utils.variable_list,
                         solve_data.working_model.MindtPy_utils.variable_list,
                         config)
    update_suboptimal_dual_bound(solve_data, main_mip_results)
    config.logger.info(
        solve_data.log_formatter.format(
            solve_data.mip_iter, 'MILP', value(MindtPy.mip_obj.expr),
            solve_data.LB, solve_data.UB, solve_data.rel_gap,
            get_main_elapsed_time(solve_data.timing)))
Ejemplo n.º 2
0
def handle_main_other_conditions(main_mip, main_mip_results, solve_data,
                                 config):
    """This function handles the result of the latest iteration of solving the MIP problem (given any of a few
    edge conditions, such as if the solution is neither infeasible nor optimal).

    Parameters
    ----------
    main_mip : Pyomo model
        The MIP main problem.
    main_mip_results : SolverResults
        Results from solving the MIP problem.
    solve_data : MindtPySolveData
        Data container that holds solve-instance data.
    config : ConfigBlock
        The specific configurations for MindtPy.

    Raises
    ------
    ValueError
        MindtPy unable to handle MILP main termination condition.
    """
    if main_mip_results.solver.termination_condition is tc.infeasible:
        handle_main_infeasible(main_mip, solve_data, config)
    elif main_mip_results.solver.termination_condition is tc.unbounded:
        temp_results = handle_main_unbounded(main_mip, solve_data, config)
    elif main_mip_results.solver.termination_condition is tc.infeasibleOrUnbounded:
        temp_results = handle_main_unbounded(main_mip, solve_data, config)
        if temp_results.solver.termination_condition is tc.infeasible:
            handle_main_infeasible(main_mip, solve_data, config)
    elif main_mip_results.solver.termination_condition is tc.maxTimeLimit:
        handle_main_max_timelimit(main_mip, main_mip_results, solve_data,
                                  config)
        solve_data.results.solver.termination_condition = tc.maxTimeLimit
    elif (main_mip_results.solver.termination_condition is tc.other
          and main_mip_results.solution.status is SolutionStatus.feasible):
        # load the solution and suppress the warning message by setting
        # solver status to ok.
        MindtPy = main_mip.MindtPy_utils
        config.logger.info('MILP solver reported feasible solution, '
                           'but not guaranteed to be optimal.')
        copy_var_list_values(
            main_mip.MindtPy_utils.variable_list,
            solve_data.working_model.MindtPy_utils.variable_list, config)
        update_suboptimal_dual_bound(solve_data, main_mip_results)
        config.logger.info(
            solve_data.log_formatter.format(
                solve_data.mip_iter, 'MILP', value(MindtPy.mip_obj.expr),
                solve_data.LB, solve_data.UB, solve_data.rel_gap,
                get_main_elapsed_time(solve_data.timing)))
    else:
        raise ValueError(
            'MindtPy unable to handle MILP main termination condition '
            'of %s. Solver message: %s' %
            (main_mip_results.solver.termination_condition,
             main_mip_results.solver.message))
Ejemplo n.º 3
0
def init_rNLP(solve_data, config):
    """Initialize the problem by solving the relaxed NLP and then store the optimal variable
    values obtained from solving the rNLP.

    Parameters
    ----------
    solve_data : MindtPySolveData
        Data container that holds solve-instance data.
    config : ConfigBlock
        The specific configurations for MindtPy.

    Raises
    ------
    ValueError
        MindtPy unable to handle the termination condition of the relaxed NLP.
    """
    m = solve_data.working_model.clone()
    config.logger.debug('Relaxed NLP: Solve relaxed integrality')
    MindtPy = m.MindtPy_utils
    TransformationFactory('core.relax_integer_vars').apply_to(m)
    nlp_args = dict(config.nlp_solver_args)
    nlpopt = SolverFactory(config.nlp_solver)
    set_solver_options(nlpopt, solve_data, config, solver_type='nlp')
    with SuppressInfeasibleWarning():
        results = nlpopt.solve(m, tee=config.nlp_solver_tee, **nlp_args)
    subprob_terminate_cond = results.solver.termination_condition
    if subprob_terminate_cond in {tc.optimal, tc.feasible, tc.locallyOptimal}:
        main_objective = MindtPy.objective_list[-1]
        if subprob_terminate_cond == tc.optimal:
            update_dual_bound(solve_data, value(main_objective.expr))
        else:
            config.logger.info('relaxed NLP is not solved to optimality.')
            update_suboptimal_dual_bound(solve_data, results)
        dual_values = list(
            m.dual[c] for c in
            MindtPy.constraint_list) if config.calculate_dual else None
        config.logger.info(
            solve_data.log_formatter.format(
                '-', 'Relaxed NLP', value(main_objective.expr), solve_data.LB,
                solve_data.UB, solve_data.rel_gap,
                get_main_elapsed_time(solve_data.timing)))
        # Add OA cut
        if config.strategy in {'OA', 'GOA', 'FP'}:
            copy_var_list_values(m.MindtPy_utils.variable_list,
                                 solve_data.mip.MindtPy_utils.variable_list,
                                 config,
                                 ignore_integrality=True)
            if config.init_strategy == 'FP':
                copy_var_list_values(
                    m.MindtPy_utils.variable_list,
                    solve_data.working_model.MindtPy_utils.variable_list,
                    config,
                    ignore_integrality=True)
            if config.strategy in {'OA', 'FP'}:
                add_oa_cuts(solve_data.mip, dual_values, solve_data, config)
            elif config.strategy == 'GOA':
                add_affine_cuts(solve_data, config)
            for var in solve_data.mip.MindtPy_utils.discrete_variable_list:
                # We don't want to trigger the reset of the global stale
                # indicator, so we will set this variable to be "stale",
                # knowing that set_value will switch it back to "not
                # stale"
                var.stale = True
                var.set_value(int(round(var.value)), skip_validation=True)
    elif subprob_terminate_cond in {tc.infeasible, tc.noSolution}:
        # TODO fail? try something else?
        config.logger.info('Initial relaxed NLP problem is infeasible. '
                           'Problem may be infeasible.')
    elif subprob_terminate_cond is tc.maxTimeLimit:
        config.logger.info(
            'NLP subproblem failed to converge within time limit.')
        solve_data.results.solver.termination_condition = tc.maxTimeLimit
    elif subprob_terminate_cond is tc.maxIterations:
        config.logger.info(
            'NLP subproblem failed to converge within iteration limit.')
    else:
        raise ValueError(
            'MindtPy unable to handle relaxed NLP termination condition '
            'of %s. Solver message: %s' %
            (subprob_terminate_cond, results.solver.message))
Ejemplo n.º 4
0
def fix_dual_bound(solve_data, config, last_iter_cuts):
    """Fix the dual bound when no-good cuts or tabu list is activated.

    Parameters
    ----------
    solve_data : MindtPySolveData
        Data container that holds solve-instance data.
    config : ConfigBlock
        The specific configurations for MindtPy.
    last_iter_cuts : bool
        Whether the cuts in the last iteration have been added.
    """
    if config.single_tree:
        config.logger.info(
            'Fix the bound to the value of one iteration before optimal solution is found.')
        try:
            if solve_data.objective_sense == minimize:
                solve_data.LB = solve_data.stored_bound[solve_data.UB]
            else:
                solve_data.UB = solve_data.stored_bound[solve_data.LB]
        except KeyError:
            config.logger.info('No stored bound found. Bound fix failed.')
    else:
        config.logger.info(
            'Solve the main problem without the last no_good cut to fix the bound.'
            'zero_tolerance is set to 1E-4')
        config.zero_tolerance = 1E-4
        # Solve NLP subproblem
        # The constraint linearization happens in the handlers
        if not last_iter_cuts:
            fixed_nlp, fixed_nlp_result = solve_subproblem(solve_data, config)
            handle_nlp_subproblem_tc(
                fixed_nlp, fixed_nlp_result, solve_data, config)

        MindtPy = solve_data.mip.MindtPy_utils
        # deactivate the integer cuts generated after the best solution was found.
        if config.strategy == 'GOA':
            try:
                if solve_data.objective_sense == minimize:
                    valid_no_good_cuts_num = solve_data.num_no_good_cuts_added[solve_data.UB]
                else:
                    valid_no_good_cuts_num = solve_data.num_no_good_cuts_added[solve_data.LB]
                if config.add_no_good_cuts:
                    for i in range(valid_no_good_cuts_num+1, len(MindtPy.cuts.no_good_cuts)+1):
                        MindtPy.cuts.no_good_cuts[i].deactivate()
                if config.use_tabu_list:
                    solve_data.integer_list = solve_data.integer_list[:valid_no_good_cuts_num]
            except KeyError:
                config.logger.info('No-good cut deactivate failed.')
        elif config.strategy == 'OA':
            # Only deactive the last OA cuts may not be correct.
            # Since integer solution may also be cut off by OA cuts due to calculation approximation.
            if config.add_no_good_cuts:
                MindtPy.cuts.no_good_cuts[len(
                    MindtPy.cuts.no_good_cuts)].deactivate()
            if config.use_tabu_list:
                solve_data.integer_list = solve_data.integer_list[:-1]
        if config.add_regularization is not None and MindtPy.find_component('mip_obj') is None:
            MindtPy.objective_list[-1].activate()
        mainopt = SolverFactory(config.mip_solver)
        # determine if persistent solver is called.
        if isinstance(mainopt, PersistentSolver):
            mainopt.set_instance(solve_data.mip, symbolic_solver_labels=True)
        if config.use_tabu_list:
            tabulist = mainopt._solver_model.register_callback(
                tabu_list.IncumbentCallback_cplex)
            tabulist.solve_data = solve_data
            tabulist.opt = mainopt
            tabulist.config = config
            mainopt._solver_model.parameters.preprocessing.reduce.set(1)
            # If the callback is used to reject incumbents, the user must set the
            # parameter c.parameters.preprocessing.reduce either to the value 1 (one)
            # to restrict presolve to primal reductions only or to 0 (zero) to disable all presolve reductions
            mainopt._solver_model.set_warning_stream(None)
            mainopt._solver_model.set_log_stream(None)
            mainopt._solver_model.set_error_stream(None)
        mip_args = dict(config.mip_solver_args)
        set_solver_options(mainopt, solve_data, config, solver_type='mip')
        main_mip_results = mainopt.solve(
            solve_data.mip, tee=config.mip_solver_tee, **mip_args)
        if main_mip_results.solver.termination_condition is tc.infeasible:
            config.logger.info(
                'Bound fix failed. The bound fix problem is infeasible')
        else:
            update_suboptimal_dual_bound(solve_data, main_mip_results)
            config.logger.info(
                'Fixed bound values: LB: {}  UB: {}'.
                format(solve_data.LB, solve_data.UB))
        # Check bound convergence
        if solve_data.LB + config.bound_tolerance >= solve_data.UB:
            solve_data.results.solver.termination_condition = tc.optimal
Ejemplo n.º 5
0
def solve_main(solve_data, config, fp=False, regularization_problem=False):
    """This function solves the MIP main problem.

    Parameters
    ----------
    solve_data : MindtPySolveData
        Data container that holds solve-instance data.
    config : ConfigBlock
        The specific configurations for MindtPy.
    fp : bool, optional
        Whether it is in the loop of feasibility pump, by default False.
    regularization_problem : bool, optional
        Whether it is solving a regularization problem, by default False.

    Returns
    -------
    solve_data.mip : Pyomo model
        The MIP stored in solve_data.
    main_mip_results : SolverResults
        Results from solving the main MIP.
    """
    if not fp and not regularization_problem:
        solve_data.mip_iter += 1

    # setup main problem
    setup_main(solve_data, config, fp, regularization_problem)
    mainopt = set_up_mip_solver(solve_data, config, regularization_problem)

    mip_args = dict(config.mip_solver_args)
    if config.mip_solver in {
            'cplex', 'cplex_persistent', 'gurobi', 'gurobi_persistent'
    }:
        mip_args['warmstart'] = True
    set_solver_options(mainopt,
                       solve_data,
                       config,
                       solver_type='mip',
                       regularization=regularization_problem)
    try:
        with time_code(
                solve_data.timing,
                'regularization main' if regularization_problem else
            ('fp main' if fp else 'main')):
            main_mip_results = mainopt.solve(solve_data.mip,
                                             tee=config.mip_solver_tee,
                                             **mip_args)
    except (ValueError, AttributeError):
        if config.single_tree:
            config.logger.warning('Single tree terminate.')
            if get_main_elapsed_time(
                    solve_data.timing) >= config.time_limit - 2:
                config.logger.warning('due to the timelimit.')
                solve_data.results.solver.termination_condition = tc.maxTimeLimit
            if config.strategy == 'GOA' or config.add_no_good_cuts:
                config.logger.warning(
                    'ValueError: Cannot load a SolverResults object with bad status: error. '
                    'MIP solver failed. This usually happens in the single-tree GOA algorithm. '
                    "No-good cuts are added and GOA algorithm doesn't converge within the time limit. "
                    'No integer solution is found, so the cplex solver will report an error status. '
                )
        return None, None
    if config.solution_pool:
        main_mip_results._solver_model = mainopt._solver_model
        main_mip_results._pyomo_var_to_solver_var_map = mainopt._pyomo_var_to_solver_var_map
    if main_mip_results.solver.termination_condition is tc.optimal:
        if config.single_tree and not config.add_no_good_cuts and not regularization_problem:
            update_suboptimal_dual_bound(solve_data, main_mip_results)
        if regularization_problem:
            config.logger.info(
                solve_data.log_formatter.format(
                    solve_data.mip_iter,
                    'Reg ' + solve_data.regularization_mip_type,
                    value(solve_data.mip.MindtPy_utils.loa_proj_mip_obj),
                    solve_data.LB, solve_data.UB, solve_data.rel_gap,
                    get_main_elapsed_time(solve_data.timing)))

    elif main_mip_results.solver.termination_condition is tc.infeasibleOrUnbounded:
        # Linear solvers will sometimes tell me that it's infeasible or
        # unbounded during presolve, but fails to distinguish. We need to
        # resolve with a solver option flag on.
        main_mip_results, _ = distinguish_mip_infeasible_or_unbounded(
            solve_data.mip, config)
        return solve_data.mip, main_mip_results

    if regularization_problem:
        solve_data.mip.MindtPy_utils.objective_constr.deactivate()
        solve_data.mip.MindtPy_utils.del_component('loa_proj_mip_obj')
        solve_data.mip.MindtPy_utils.cuts.del_component('obj_reg_estimate')
        if config.add_regularization == 'level_L1':
            solve_data.mip.MindtPy_utils.del_component('L1_obj')
        elif config.add_regularization == 'level_L_infinity':
            solve_data.mip.MindtPy_utils.del_component('L_infinity_obj')

    return solve_data.mip, main_mip_results