Ejemplo n.º 1
0
def MindtPy_initialize_master(solve_data, config):
    """Initialize the decomposition algorithm.
    This includes generating the initial cuts require to build the master
    problem.
    """
    # if single tree is activated, we need to add bounds for unbounded variables in nonlinear constraints to avoid unbounded master problem.
    if config.single_tree:
        var_bound_add(solve_data, config)

    m = solve_data.mip = solve_data.working_model.clone()
    MindtPy = m.MindtPy_utils
    m.dual.deactivate()

    if config.strategy == 'OA':
        calc_jacobians(solve_data, config)  # preload jacobians
        MindtPy.MindtPy_linear_cuts.oa_cuts = ConstraintList(
            doc='Outer approximation cuts')
    # elif config.strategy == 'ECP':
    #     calc_jacobians(solve_data, config)  # preload jacobians
    #     MindtPy.MindtPy_linear_cuts.ecp_cuts = ConstraintList(
    #         doc='Extended Cutting Planes')
    # elif config.strategy == 'PSC':
    #     detect_nonlinear_vars(solve_data, config)
    #     MindtPy.MindtPy_linear_cuts.psc_cuts = ConstraintList(
    #         doc='Partial surrogate cuts')
    # elif config.strategy == 'GBD':
    #     MindtPy.MindtPy_linear_cuts.gbd_cuts = ConstraintList(
    #         doc='Generalized Benders cuts')

    # Set default initialization_strategy
    if config.init_strategy is None:
        if config.strategy == 'OA':
            config.init_strategy = 'rNLP'
        else:
            config.init_strategy = 'max_binary'
    # Do the initialization
    elif config.init_strategy == 'rNLP':
        init_rNLP(solve_data, config)
    elif config.init_strategy == 'max_binary':
        init_max_binaries(solve_data, config)
        # if config.strategy == 'ECP':
        #     add_ecp_cut(solve_data, config)
        # else:

        fixed_nlp, fixed_nlp_result = solve_NLP_subproblem(solve_data, config)
        if fixed_nlp_result.solver.termination_condition is tc.optimal or fixed_nlp_result.solver.termination_condition is tc.locallyOptimal:
            handle_NLP_subproblem_optimal(fixed_nlp, solve_data, config)
        elif fixed_nlp_result.solver.termination_condition is tc.infeasible:
            handle_NLP_subproblem_infeasible(fixed_nlp, solve_data, config)
        else:
            handle_NLP_subproblem_other_termination(fixed_nlp, fixed_nlp_result.solver.termination_condition,
                                                    solve_data, config)
Ejemplo n.º 2
0
def MindtPy_iteration_loop(solve_data, config):
    working_model = solve_data.working_model
    main_objective = next(
        working_model.component_data_objects(Objective, active=True))
    while solve_data.mip_iter < config.iteration_limit:

        config.logger.info('---MindtPy Master Iteration %s---' %
                           solve_data.mip_iter)

        if algorithm_should_terminate(solve_data, config, check_cycling=False):
            break

        solve_data.mip_subiter = 0
        # solve MILP master problem
        if config.strategy == 'OA':
            master_mip, master_mip_results = solve_OA_master(
                solve_data, config)
            if master_mip_results.solver.termination_condition is tc.optimal:
                handle_master_mip_optimal(master_mip, solve_data, config)
            else:
                handle_master_mip_other_conditions(master_mip,
                                                   master_mip_results,
                                                   solve_data, config)
            # Call the MILP post-solve callback
            config.call_after_master_solve(master_mip, solve_data)
        else:
            raise NotImplementedError()

        if algorithm_should_terminate(solve_data, config, check_cycling=True):
            break

        if config.single_tree is False:  # if we don't use lazy callback, i.e. LP_NLP
            # Solve NLP subproblem
            # The constraint linearization happens in the handlers
            fixed_nlp, fixed_nlp_result = solve_NLP_subproblem(
                solve_data, config)
            if fixed_nlp_result.solver.termination_condition is tc.optimal or fixed_nlp_result.solver.termination_condition is tc.locallyOptimal:
                handle_NLP_subproblem_optimal(fixed_nlp, solve_data, config)
            elif fixed_nlp_result.solver.termination_condition is tc.infeasible:
                handle_NLP_subproblem_infeasible(fixed_nlp, solve_data, config)
            else:
                handle_NLP_subproblem_other_termination(
                    fixed_nlp, fixed_nlp_result.solver.termination_condition,
                    solve_data, config)
            # Call the NLP post-solve callback
            config.call_after_subproblem_solve(fixed_nlp, solve_data)
Ejemplo n.º 3
0
def MindtPy_iteration_loop(solve_data, config):
    working_model = solve_data.working_model
    main_objective = next(
        working_model.component_data_objects(Objective, active=True))
    while solve_data.mip_iter < config.iteration_limit:
        config.logger.info('---MindtPy Master Iteration %s---' %
                           solve_data.mip_iter)

        if algorithm_should_terminate(solve_data, config):
            break

        solve_data.mip_subiter = 0
        # solve MILP master problem
        if config.strategy == 'OA':
            master_mip, master_mip_results = solve_OA_master(
                solve_data, config)
            if master_mip_results.solver.termination_condition is tc.optimal:
                handle_master_mip_optimal(master_mip, solve_data, config)
            else:
                handle_master_mip_other_conditions(master_mip,
                                                   master_mip_results,
                                                   solve_data, config)
            # Call the MILP post-solve callback
            config.call_after_master_solve(master_mip, solve_data)
        else:
            raise NotImplementedError()

        if algorithm_should_terminate(solve_data, config):
            break

        # Solve NLP subproblem
        # The constraint linearization happens in the handlers
        fix_nlp, fix_nlp_result = solve_NLP_subproblem(solve_data, config)
        if fix_nlp_result.solver.termination_condition is tc.optimal:
            handle_NLP_subproblem_optimal(fix_nlp, solve_data, config)
        elif fix_nlp_result.solver.termination_condition is tc.infeasible:
            handle_NLP_subproblem_infeasible(fix_nlp, solve_data, config)
        else:
            handle_NLP_subproblem_other_termination(
                fix_nlp, fix_nlp_result.solver.termination_condition,
                solve_data, config)
        # Call the NLP post-solve callback
        config.call_after_subproblem_solve(fix_nlp, solve_data)

        if config.strategy == 'PSC':
            # If the hybrid algorithm is not making progress, switch to OA.
            progress_required = 1E-6
            if main_objective.sense == minimize:
                log = solve_data.LB_progress
                sign_adjust = 1
            else:
                log = solve_data.UB_progress
                sign_adjust = -1
            # Maximum number of iterations in which the lower (optimistic)
            # bound does not improve before switching to OA
            max_nonimprove_iter = 5
            making_progress = True
            # TODO-romeo Unneccesary for OA and LOA, right?
            for i in range(1, max_nonimprove_iter + 1):
                try:
                    if (sign_adjust * log[-i] <=
                        (log[-i - 1] + progress_required) * sign_adjust):
                        making_progress = False
                    else:
                        making_progress = True
                        break
                except IndexError:
                    # Not enough history yet, keep going.
                    making_progress = True
                    break
            if not making_progress and (config.strategy == 'hPSC'
                                        or config.strategy == 'PSC'):
                config.logger.info(
                    'Not making enough progress for {} iterations. '
                    'Switching to OA.'.format(max_nonimprove_iter))
                config.strategy = 'OA'
Ejemplo n.º 4
0
def bound_fix(solve_data, config, last_iter_cuts):
    if config.single_tree:
        config.logger.info(
            'Fix the bound to the value of one iteration before optimal solution is found.'
        )
        if solve_data.results.problem.sense == ProblemSense.minimize:
            solve_data.LB = solve_data.stored_bound[solve_data.UB]
        else:
            solve_data.UB = solve_data.stored_bound[solve_data.LB]
    else:
        config.logger.info(
            'Solve the master problem without the last nogood 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 last_iter_cuts is False:
            fixed_nlp, fixed_nlp_result = solve_NLP_subproblem(
                solve_data, config)
            if fixed_nlp_result.solver.termination_condition in {
                    tc.optimal, tc.locallyOptimal, tc.feasible
            }:
                handle_NLP_subproblem_optimal(fixed_nlp, solve_data, config)
            elif fixed_nlp_result.solver.termination_condition is tc.infeasible:
                handle_NLP_subproblem_infeasible(fixed_nlp, solve_data, config)
            else:
                handle_NLP_subproblem_other_termination(
                    fixed_nlp, fixed_nlp_result.solver.termination_condition,
                    solve_data, config)

        MindtPy = solve_data.mip.MindtPy_utils
        # only deactivate the last integer cut.
        if config.strategy == 'GOA':
            if solve_data.results.problem.sense == ProblemSense.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]
            for i in range(valid_no_good_cuts_num + 1,
                           len(MindtPy.MindtPy_linear_cuts.integer_cuts) + 1):
                MindtPy.MindtPy_linear_cuts.integer_cuts[i].deactivate()
        elif config.strategy == 'OA':
            MindtPy.MindtPy_linear_cuts.integer_cuts[len(
                MindtPy.MindtPy_linear_cuts.integer_cuts)].deactivate()
        # MindtPy.MindtPy_linear_cuts.oa_cuts.activate()
        masteropt = SolverFactory(config.mip_solver)
        # determine if persistent solver is called.
        if isinstance(masteropt, PersistentSolver):
            masteropt.set_instance(solve_data.mip, symbolic_solver_labels=True)
        mip_args = dict(config.mip_solver_args)
        elapsed = get_main_elapsed_time(solve_data.timing)
        remaining = int(max(config.time_limit - elapsed, 1))
        if config.mip_solver == 'gams':
            mip_args['add_options'] = mip_args.get('add_options', [])
            mip_args['add_options'].append('option optcr=0.001;')
        if config.threads > 0:
            masteropt.options["threads"] = config.threads
        master_mip_results = masteropt.solve(solve_data.mip,
                                             tee=config.solver_tee,
                                             **mip_args)
        main_objective = next(
            solve_data.working_model.component_data_objects(Objective,
                                                            active=True))
        if main_objective.sense == minimize:
            solve_data.LB = max([master_mip_results.problem.lower_bound] +
                                solve_data.LB_progress[:-1])
            solve_data.LB_progress.append(solve_data.LB)
        else:
            solve_data.UB = min([master_mip_results.problem.upper_bound] +
                                solve_data.UB_progress[:-1])
            solve_data.UB_progress.append(solve_data.UB)
        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 MindtPy_iteration_loop(solve_data, config):
    """
    Main loop for MindtPy Algorithms

    This is the outermost function for the algorithms in this package; this function controls the progression of
    solving the model.

    Parameters
    ----------
    solve_data: MindtPy Data Container
        data container that holds solve-instance data
    config: ConfigBlock
        contains the specific configurations for the algorithm
    """
    working_model = solve_data.working_model
    main_objective = next(
        working_model.component_data_objects(Objective, active=True))
    while solve_data.mip_iter < config.iteration_limit:

        config.logger.info('---MindtPy Master Iteration %s---' %
                           solve_data.mip_iter)

        solve_data.mip_subiter = 0
        # solve MILP master problem
        if config.strategy in {'OA', 'GOA', 'ECP'}:
            master_mip, master_mip_results = solve_OA_master(
                solve_data, config)
            if config.single_tree is False:
                if master_mip_results.solver.termination_condition is tc.optimal:
                    handle_master_mip_optimal(master_mip, solve_data, config)
                elif master_mip_results.solver.termination_condition is tc.infeasible:
                    handle_master_mip_infeasible(master_mip, solve_data,
                                                 config)
                    last_iter_cuts = True
                    break
                else:
                    handle_master_mip_other_conditions(master_mip,
                                                       master_mip_results,
                                                       solve_data, config)
                # Call the MILP post-solve callback
                config.call_after_master_solve(master_mip, solve_data)
        else:
            raise NotImplementedError()

        if algorithm_should_terminate(solve_data, config, check_cycling=True):
            last_iter_cuts = False
            break

        if config.single_tree is False and config.strategy != 'ECP':  # if we don't use lazy callback, i.e. LP_NLP
            # Solve NLP subproblem
            # The constraint linearization happens in the handlers
            fixed_nlp, fixed_nlp_result = solve_NLP_subproblem(
                solve_data, config)
            if fixed_nlp_result.solver.termination_condition in {
                    tc.optimal, tc.locallyOptimal, tc.feasible
            }:
                handle_NLP_subproblem_optimal(fixed_nlp, solve_data, config)
            elif fixed_nlp_result.solver.termination_condition is tc.infeasible:
                handle_NLP_subproblem_infeasible(fixed_nlp, solve_data, config)
            else:
                handle_NLP_subproblem_other_termination(
                    fixed_nlp, fixed_nlp_result.solver.termination_condition,
                    solve_data, config)
            # Call the NLP post-solve callback
            config.call_after_subproblem_solve(fixed_nlp, solve_data)

        if algorithm_should_terminate(solve_data, config, check_cycling=False):
            last_iter_cuts = True
            break

        if config.strategy == 'ECP':
            add_ecp_cuts(solve_data.mip, solve_data, config)

        # if config.strategy == 'PSC':
        #     # If the hybrid algorithm is not making progress, switch to OA.
        #     progress_required = 1E-6
        #     if main_objective.sense == minimize:
        #         log = solve_data.LB_progress
        #         sign_adjust = 1
        #     else:
        #         log = solve_data.UB_progress
        #         sign_adjust = -1
        #     # Maximum number of iterations in which the lower (optimistic)
        #     # bound does not improve before switching to OA
        #     max_nonimprove_iter = 5
        #     making_progress = True
        #     # TODO-romeo Unneccesary for OA and LOA, right?
        #     for i in range(1, max_nonimprove_iter + 1):
        #         try:
        #             if (sign_adjust * log[-i]
        #                     <= (log[-i - 1] + progress_required)
        #                     * sign_adjust):
        #                 making_progress = False
        #             else:
        #                 making_progress = True
        #                 break
        #         except IndexError:
        #             # Not enough history yet, keep going.
        #             making_progress = True
        #             break
        #     if not making_progress and (
        #             config.strategy == 'hPSC' or
        #             config.strategy == 'PSC'):
        #         config.logger.info(
        #             'Not making enough progress for {} iterations. '
        #             'Switching to OA.'.format(max_nonimprove_iter))
        #         config.strategy = 'OA'

    # if add_nogood_cuts is True, the bound obtained in the last iteration is no reliable.
    # we correct it after the iteration.
    if config.add_nogood_cuts:
        bound_fix(solve_data, config, last_iter_cuts)
Ejemplo n.º 6
0
def MindtPy_initialize_master(solve_data, config):
    """
    Initializes the decomposition algorithm and creates the master MIP/MILP problem.

    This function initializes the decomposition problem, which includes generating the initial cuts required to
    build the master MIP/MILP

    Parameters
    ----------
    solve_data: MindtPy Data Container
        data container that holds solve-instance data
    config: ConfigBlock
        contains the specific configurations for the algorithm
    """
    # if single tree is activated, we need to add bounds for unbounded variables in nonlinear constraints to avoid unbounded master problem.
    if config.single_tree:
        var_bound_add(solve_data, config)

    m = solve_data.mip = solve_data.working_model.clone()
    MindtPy = m.MindtPy_utils
    if config.use_dual:
        m.dual.deactivate()

    if config.strategy == 'OA':
        calc_jacobians(solve_data, config)  # preload jacobians
        MindtPy.MindtPy_linear_cuts.oa_cuts = ConstraintList(
            doc='Outer approximation cuts')
    elif config.strategy == 'ECP':
        calc_jacobians(solve_data, config)  # preload jacobians
        MindtPy.MindtPy_linear_cuts.ecp_cuts = ConstraintList(
            doc='Extended Cutting Planes')
    # elif config.strategy == 'PSC':
    #     detect_nonlinear_vars(solve_data, config)
    #     MindtPy.MindtPy_linear_cuts.psc_cuts = ConstraintList(
    #         doc='Partial surrogate cuts')
    # elif config.strategy == 'GBD':
    #     MindtPy.MindtPy_linear_cuts.gbd_cuts = ConstraintList(
    #         doc='Generalized Benders cuts')

    # Set default initialization_strategy
    if config.init_strategy is None:
        if config.strategy in {'OA', 'GOA'}:
            config.init_strategy = 'rNLP'
        else:
            config.init_strategy = 'max_binary'

    config.logger.info(
        '{} is the initial strategy being used.'
        '\n'.format(
            config.init_strategy))
    # Do the initialization
    if config.init_strategy == 'rNLP':
        init_rNLP(solve_data, config)
    elif config.init_strategy == 'max_binary':
        init_max_binaries(solve_data, config)
    elif config.init_strategy == 'initial_binary':
        if config.strategy != 'ECP':
            fixed_nlp, fixed_nlp_result = solve_NLP_subproblem(
                solve_data, config)
            if fixed_nlp_result.solver.termination_condition in {tc.optimal, tc.locallyOptimal, tc.feasible}:
                handle_NLP_subproblem_optimal(fixed_nlp, solve_data, config)
            elif fixed_nlp_result.solver.termination_condition is tc.infeasible:
                handle_NLP_subproblem_infeasible(fixed_nlp, solve_data, config)
            else:
                handle_NLP_subproblem_other_termination(fixed_nlp, fixed_nlp_result.solver.termination_condition,
                                                        solve_data, config)