Esempio n. 1
0
 def test_inactive_constraints(self):
     m = ConcreteModel()
     m.x = Var()
     m.c1 = Constraint(expr=m.x == 1)
     m.c2 = Constraint(expr=m.x == 2)
     m.o = Objective(expr=m.x)
     self.assertFalse(satisfiable(m))
     m.c2.deactivate()
     self.assertTrue(satisfiable(m))
Esempio n. 2
0
 def test_inactive_constraints(self):
     m = ConcreteModel()
     m.x = Var()
     m.c1 = Constraint(expr=m.x == 1)
     m.c2 = Constraint(expr=m.x == 2)
     m.o = Objective(expr=m.x)
     self.assertFalse(satisfiable(m))
     m.c2.deactivate()
     self.assertTrue(satisfiable(m))
Esempio n. 3
0
 def test_8PP_deactive(self):
     exfile = import_file(
         join(exdir, 'eight_process', 'eight_proc_model.py'))
     m = exfile.build_eight_process_flowsheet()
     for djn in m.component_data_objects(ctype=Disjunction):
         djn.deactivate()
     self.assertTrue(satisfiable(m) is not False)
Esempio n. 4
0
def _prescreen_node(node_data, node_model, solve_data):
    config = solve_data.config
    # Check node for satisfiability if sat-solver is enabled
    if config.check_sat and satisfiable(node_model, config.logger) is False:
        if node_data.node_count == 0:
            config.logger.info(
                "Root node is not satisfiable. Problem is infeasible.")
        else:
            config.logger.info("SAT solver pruned node %s" %
                               node_data.node_count)
        new_lb = new_ub = float('inf')
    else:
        # Solve model subproblem
        if config.solve_local_rnGDP:
            solve_data.config.logger.debug(
                "Screening node %s with LB %.10g and %s inactive disjunctions."
                % (node_data.node_count, node_data.obj_lb,
                   node_data.num_unbranched_disjunctions))
            new_lb, new_ub = _solve_local_rnGDP_subproblem(
                node_model, solve_data)
        else:
            new_lb, new_ub = float('-inf'), float('inf')
        new_lb = max(node_data.obj_lb, new_lb)

    new_node_data = node_data._replace(obj_lb=new_lb,
                                       obj_ub=new_ub,
                                       is_screened=True)
    return new_node_data
Esempio n. 5
0
 def test_8PP_deactive(self):
     exfile = import_file(
         join(exdir, 'eight_process', 'eight_proc_model.py'))
     m = exfile.build_eight_process_flowsheet()
     for djn in m.component_data_objects(ctype=Disjunction):
         djn.deactivate()
     self.assertTrue(satisfiable(m) is not False)
Esempio n. 6
0
 def test_simple_unsat_model(self):
     m = ConcreteModel()
     m.x = Var()
     m.c1 = Constraint(expr=1 == m.x)
     m.c2 = Constraint(expr=2 == m.x)
     m.o = Objective(expr=m.x)
     self.assertFalse(satisfiable(m))
Esempio n. 7
0
 def test_simple_unsat_model(self):
     m = ConcreteModel()
     m.x = Var()
     m.c1 = Constraint(expr=1 == m.x)
     m.c2 = Constraint(expr=2 == m.x)
     m.o = Objective(expr=m.x)
     self.assertFalse(satisfiable(m))
Esempio n. 8
0
 def test_binary_expressions(self):
     m = ConcreteModel()
     m.x = Var()
     m.y = Var()
     m.z = Var()
     m.c = Constraint(expr=0 <= m.x + m.y - m.z * m.y / m.x + 7)
     m.o = Objective(expr=m.x)
     self.assertTrue(satisfiable(m))
Esempio n. 9
0
 def test_binary_expressions(self):
     m = ConcreteModel()
     m.x = Var()
     m.y = Var()
     m.z = Var()
     m.c = Constraint(expr=0 <= m.x + m.y - m.z * m.y / m.x + 7)
     m.o = Objective(expr=m.x)
     self.assertTrue(satisfiable(m))
Esempio n. 10
0
 def test_disjunction_unsat(self):
     m = ConcreteModel()
     m.x1 = Var(bounds=(0, 8))
     m.x2 = Var(bounds=(0, 8))
     m.obj = Objective(expr=m.x1 + m.x2, sense=minimize)
     m.y1 = Disjunct()
     m.y2 = Disjunct()
     m.y1.c1 = Constraint(expr=m.x1 >= 9)
     m.y1.c2 = Constraint(expr=m.x2 >= 2)
     m.y2.c1 = Constraint(expr=m.x1 >= 3)
     m.y2.c2 = Constraint(expr=m.x2 >= 9)
     m.djn = Disjunction(expr=[m.y1, m.y2])
     self.assertFalse(satisfiable(m))
Esempio n. 11
0
 def test_disjunction_unsat(self):
     m = ConcreteModel()
     m.x1 = Var(bounds=(0, 8))
     m.x2 = Var(bounds=(0, 8))
     m.obj = Objective(expr=m.x1 + m.x2, sense=minimize)
     m.y1 = Disjunct()
     m.y2 = Disjunct()
     m.y1.c1 = Constraint(expr=m.x1 >= 9)
     m.y1.c2 = Constraint(expr=m.x2 >= 2)
     m.y2.c1 = Constraint(expr=m.x1 >= 3)
     m.y2.c2 = Constraint(expr=m.x2 >= 9)
     m.djn = Disjunction(expr=[m.y1, m.y2])
     self.assertFalse(satisfiable(m))
Esempio n. 12
0
 def test_unary_expressions(self):
     m = ConcreteModel()
     m.x = Var()
     m.y = Var()
     m.z = Var()
     m.a = Var()
     m.b = Var()
     m.c = Var()
     m.d = Var()
     m.c1 = Constraint(expr=0 <= sin(m.x))
     m.c2 = Constraint(expr=0 <= cos(m.y))
     m.c3 = Constraint(expr=0 <= tan(m.z))
     m.c4 = Constraint(expr=0 <= asin(m.a))
     m.c5 = Constraint(expr=0 <= acos(m.b))
     m.c6 = Constraint(expr=0 <= atan(m.c))
     m.c7 = Constraint(expr=0 <= sqrt(m.d))
     m.o = Objective(expr=m.x)
     self.assertTrue(satisfiable(m) is not False)
Esempio n. 13
0
 def test_unary_expressions(self):
     m = ConcreteModel()
     m.x = Var()
     m.y = Var()
     m.z = Var()
     m.a = Var()
     m.b = Var()
     m.c = Var()
     m.d = Var()
     m.c1 = Constraint(expr=0 <= sin(m.x))
     m.c2 = Constraint(expr=0 <= cos(m.y))
     m.c3 = Constraint(expr=0 <= tan(m.z))
     m.c4 = Constraint(expr=0 <= asin(m.a))
     m.c5 = Constraint(expr=0 <= acos(m.b))
     m.c6 = Constraint(expr=0 <= atan(m.c))
     m.c7 = Constraint(expr=0 <= sqrt(m.d))
     m.o = Objective(expr=m.x)
     self.assertTrue(satisfiable(m) is not False)
Esempio n. 14
0
 def test_multiple_disjunctions_sat(self):
     m = ConcreteModel()
     m.x1 = Var(bounds=(0, 8))
     m.x2 = Var(bounds=(0, 8))
     m.obj = Objective(expr=m.x1 + m.x2, sense=minimize)
     m.y1 = Disjunct()
     m.y2 = Disjunct()
     m.y1.c1 = Constraint(expr=m.x1 >= 2)
     m.y1.c2 = Constraint(expr=m.x2 >= 2)
     m.y2.c1 = Constraint(expr=m.x1 >= 1)
     m.y2.c2 = Constraint(expr=m.x2 >= 1)
     m.djn1 = Disjunction(expr=[m.y1, m.y2])
     m.z1 = Disjunct()
     m.z2 = Disjunct()
     m.z1.c1 = Constraint(expr=m.x1 <= 1)
     m.z1.c2 = Constraint(expr=m.x2 <= 1)
     m.z2.c1 = Constraint(expr=m.x1 <= 0)
     m.z2.c2 = Constraint(expr=m.x2 <= 0)
     m.djn2 = Disjunction(expr=[m.z1, m.z2])
     self.assertTrue(satisfiable(m))
Esempio n. 15
0
 def test_multiple_disjunctions_sat(self):
     m = ConcreteModel()
     m.x1 = Var(bounds=(0, 8))
     m.x2 = Var(bounds=(0, 8))
     m.obj = Objective(expr=m.x1 + m.x2, sense=minimize)
     m.y1 = Disjunct()
     m.y2 = Disjunct()
     m.y1.c1 = Constraint(expr=m.x1 >= 2)
     m.y1.c2 = Constraint(expr=m.x2 >= 2)
     m.y2.c1 = Constraint(expr=m.x1 >= 1)
     m.y2.c2 = Constraint(expr=m.x2 >= 1)
     m.djn1 = Disjunction(expr=[m.y1, m.y2])
     m.z1 = Disjunct()
     m.z2 = Disjunct()
     m.z1.c1 = Constraint(expr=m.x1 <= 1)
     m.z1.c2 = Constraint(expr=m.x2 <= 1)
     m.z2.c1 = Constraint(expr=m.x1 <= 0)
     m.z2.c2 = Constraint(expr=m.x2 <= 0)
     m.djn2 = Disjunction(expr=[m.z1, m.z2])
     self.assertTrue(satisfiable(m))
Esempio n. 16
0
 def test_binary_domains(self):
     m = ConcreteModel()
     m.x1 = Var(domain=Binary)
     m.c1 = Constraint(expr=m.x1 == 2)
     self.assertFalse(satisfiable(m))
Esempio n. 17
0
 def test_bounds_sat(self):
     m = ConcreteModel()
     m.x = Var(bounds=(0, 5))
     m.c1 = Constraint(expr=4.99 == m.x)
     m.o = Objective(expr=m.x)
     self.assertTrue(satisfiable(m))
Esempio n. 18
0
    def solve(self, model, **kwds):
        config = self.CONFIG(kwds.pop('options', {}))
        config.set_value(kwds)
        return SolverFactory('gdpopt').solve(
            model,
            strategy='LBB',
            minlp_solver=config.solver,
            minlp_solver_args=config.solver_args,
            tee=config.tee,
            check_sat=config.check_sat,
            logger=config.logger,
            time_limit=config.time_limit)

        # Validate model to be used with gdpbb
        self.validate_model(model)
        # Set solver as an MINLP
        solve_data = GDPbbSolveData()
        solve_data.timing = Container()
        solve_data.original_model = model
        solve_data.results = SolverResults()

        old_logger_level = config.logger.getEffectiveLevel()
        with time_code(solve_data.timing, 'total', is_main_timer=True), \
                restore_logger_level(config.logger), \
                create_utility_block(model, 'GDPbb_utils', solve_data):
            if config.tee and old_logger_level > logging.INFO:
                # If the logger does not already include INFO, include it.
                config.logger.setLevel(logging.INFO)
            config.logger.info(
                "Starting GDPbb version %s using %s as subsolver" %
                (".".join(map(str, self.version())), config.solver))

            # Setup results
            solve_data.results.solver.name = 'GDPbb - %s' % (str(
                config.solver))
            setup_results_object(solve_data, config)

            # clone original model for root node of branch and bound
            root = solve_data.working_model = solve_data.original_model.clone()

            # get objective sense
            process_objective(solve_data, config)
            objectives = solve_data.original_model.component_data_objects(
                Objective, active=True)
            obj = next(objectives, None)
            solve_data.results.problem.sense = obj.sense

            # set up lists to keep track of which disjunctions have been covered.

            # this list keeps track of the relaxed disjunctions
            root.GDPbb_utils.unenforced_disjunctions = list(
                disjunction
                for disjunction in root.GDPbb_utils.disjunction_list
                if disjunction.active)

            root.GDPbb_utils.deactivated_constraints = ComponentSet([
                constr
                for disjunction in root.GDPbb_utils.unenforced_disjunctions
                for disjunct in disjunction.disjuncts
                for constr in disjunct.component_data_objects(ctype=Constraint,
                                                              active=True)
                if constr.body.polynomial_degree() not in (1, 0)
            ])
            # Deactivate nonlinear constraints in unenforced disjunctions
            for constr in root.GDPbb_utils.deactivated_constraints:
                constr.deactivate()

            # Add the BigM suffix if it does not already exist. Used later during nonlinear constraint activation.
            if not hasattr(root, 'BigM'):
                root.BigM = Suffix()

            # Pre-screen that none of the disjunctions are already predetermined due to the disjuncts being fixed
            # to True/False values.
            # TODO this should also be done within the loop, but we aren't handling it right now.
            # Should affect efficiency, but not correctness.
            root.GDPbb_utils.disjuncts_fixed_True = ComponentSet()
            # Only find top-level (non-nested) disjunctions
            for disjunction in root.component_data_objects(Disjunction,
                                                           active=True):
                fixed_true_disjuncts = [
                    disjunct for disjunct in disjunction.disjuncts
                    if disjunct.indicator_var.fixed
                    and disjunct.indicator_var.value == 1
                ]
                fixed_false_disjuncts = [
                    disjunct for disjunct in disjunction.disjuncts
                    if disjunct.indicator_var.fixed
                    and disjunct.indicator_var.value == 0
                ]
                for disjunct in fixed_false_disjuncts:
                    disjunct.deactivate()
                if len(fixed_false_disjuncts) == len(
                        disjunction.disjuncts) - 1:
                    # all but one disjunct in the disjunction is fixed to False. Remaining one must be true.
                    if not fixed_true_disjuncts:
                        fixed_true_disjuncts = [
                            disjunct for disjunct in disjunction.disjuncts
                            if disjunct not in fixed_false_disjuncts
                        ]
                # Reactivate the fixed-true disjuncts
                for disjunct in fixed_true_disjuncts:
                    newly_activated = ComponentSet()
                    for constr in disjunct.component_data_objects(Constraint):
                        if constr in root.GDPbb_utils.deactivated_constraints:
                            newly_activated.add(constr)
                            constr.activate()
                            # Set the big M value for the constraint
                            root.BigM[constr] = 1
                            # Note: we use a default big M value of 1
                            # because all non-selected disjuncts should be deactivated.
                            # Therefore, none of the big M transformed nonlinear constraints will need to be relaxed.
                            # The default M value should therefore be irrelevant.
                    root.GDPbb_utils.deactivated_constraints -= newly_activated
                    root.GDPbb_utils.disjuncts_fixed_True.add(disjunct)

                if fixed_true_disjuncts:
                    assert disjunction.xor, "GDPbb only handles disjunctions in which one term can be selected. " \
                        "%s violates this assumption." % (disjunction.name, )
                    root.GDPbb_utils.unenforced_disjunctions.remove(
                        disjunction)

            # Check satisfiability
            if config.check_sat and satisfiable(root, config.logger) is False:
                # Problem is not satisfiable. Problem is infeasible.
                obj_value = obj_sign * float('inf')
            else:
                # solve the root node
                config.logger.info("Solving the root node.")
                obj_value, result, var_values = self.subproblem_solve(
                    root, config)

            if obj_sign * obj_value == float('inf'):
                config.logger.info(
                    "Model was found to be infeasible at the root node. Elapsed %.2f seconds."
                    % get_main_elapsed_time(solve_data.timing))
                if solve_data.results.problem.sense == minimize:
                    solve_data.results.problem.lower_bound = float('inf')
                    solve_data.results.problem.upper_bound = None
                else:
                    solve_data.results.problem.lower_bound = None
                    solve_data.results.problem.upper_bound = float('-inf')
                solve_data.results.solver.timing = solve_data.timing
                solve_data.results.solver.iterations = 0
                solve_data.results.solver.termination_condition = tc.infeasible
                return solve_data.results

            # initialize minheap for Branch and Bound algorithm
            # Heap structure: (ordering tuple, model)
            # Ordering tuple: (objective value, disjunctions_left, -total_nodes_counter)
            #  - select solutions with lower objective value,
            #    then fewer disjunctions left to explore (depth first),
            #    then more recently encountered (tiebreaker)
            heap = []
            total_nodes_counter = 0
            disjunctions_left = len(root.GDPbb_utils.unenforced_disjunctions)
            heapq.heappush(heap,
                           ((obj_sign * obj_value, disjunctions_left,
                             -total_nodes_counter), root, result, var_values))

            # loop to branch through the tree
            while len(heap) > 0:
                # pop best model off of heap
                sort_tuple, incumbent_model, incumbent_results, incumbent_var_values = heapq.heappop(
                    heap)
                incumbent_obj_value, disjunctions_left, _ = sort_tuple

                config.logger.info(
                    "Exploring node with LB %.10g and %s inactive disjunctions."
                    % (incumbent_obj_value, disjunctions_left))

                # if all the originally active disjunctions are active, solve and
                # return solution
                if disjunctions_left == 0:
                    config.logger.info("Model solved.")
                    # Model is solved. Copy over solution values.
                    original_model = solve_data.original_model
                    for orig_var, val in zip(
                            original_model.GDPbb_utils.variable_list,
                            incumbent_var_values):
                        orig_var.value = val

                    solve_data.results.problem.lower_bound = incumbent_results.problem.lower_bound
                    solve_data.results.problem.upper_bound = incumbent_results.problem.upper_bound
                    solve_data.results.solver.timing = solve_data.timing
                    solve_data.results.solver.iterations = total_nodes_counter
                    solve_data.results.solver.termination_condition = incumbent_results.solver.termination_condition
                    return solve_data.results

                # Pick the next disjunction to branch on
                next_disjunction = incumbent_model.GDPbb_utils.unenforced_disjunctions[
                    0]
                config.logger.info("Branching on disjunction %s" %
                                   next_disjunction.name)
                assert next_disjunction.xor, "GDPbb only handles disjunctions in which one term can be selected. " \
                    "%s violates this assumption." % (next_disjunction.name, )

                new_nodes_counter = 0

                for i, disjunct in enumerate(next_disjunction.disjuncts):
                    # Create one branch for each of the disjuncts on the disjunction

                    if any(disj.indicator_var.fixed
                           and disj.indicator_var.value == 1
                           for disj in next_disjunction.disjuncts
                           if disj is not disjunct):
                        # If any other disjunct is fixed to 1 and an xor relationship applies,
                        # then this disjunct cannot be activated.
                        continue

                    # Check time limit
                    if get_main_elapsed_time(
                            solve_data.timing) >= config.time_limit:
                        if solve_data.results.problem.sense == minimize:
                            solve_data.results.problem.lower_bound = incumbent_obj_value
                            solve_data.results.problem.upper_bound = float(
                                'inf')
                        else:
                            solve_data.results.problem.lower_bound = float(
                                '-inf')
                            solve_data.results.problem.upper_bound = incumbent_obj_value
                        config.logger.info('GDPopt unable to converge bounds '
                                           'before time limit of {} seconds. '
                                           'Elapsed: {} seconds'.format(
                                               config.time_limit,
                                               get_main_elapsed_time(
                                                   solve_data.timing)))
                        config.logger.info(
                            'Final bound values: LB: {}  UB: {}'.format(
                                solve_data.results.problem.lower_bound,
                                solve_data.results.problem.upper_bound))
                        solve_data.results.solver.timing = solve_data.timing
                        solve_data.results.solver.iterations = total_nodes_counter
                        solve_data.results.solver.termination_condition = tc.maxTimeLimit
                        return solve_data.results

                    # Branch on the disjunct
                    child = incumbent_model.clone()
                    # TODO I am leaving the old branching system in place, but there should be
                    # something better, ideally that deals with nested disjunctions as well.
                    disjunction_to_branch = child.GDPbb_utils.unenforced_disjunctions.pop(
                        0)
                    child_disjunct = disjunction_to_branch.disjuncts[i]
                    child_disjunct.indicator_var.fix(1)
                    # Deactivate (and fix to 0) other disjuncts on the disjunction
                    for disj in disjunction_to_branch.disjuncts:
                        if disj is not child_disjunct:
                            disj.deactivate()
                    # Activate nonlinear constraints on the newly fixed child disjunct
                    newly_activated = ComponentSet()
                    for constr in child_disjunct.component_data_objects(
                            Constraint):
                        if constr in child.GDPbb_utils.deactivated_constraints:
                            newly_activated.add(constr)
                            constr.activate()
                            # Set the big M value for the constraint
                            child.BigM[constr] = 1
                            # Note: we use a default big M value of 1
                            # because all non-selected disjuncts should be deactivated.
                            # Therefore, none of the big M transformed nonlinear constraints will need to be relaxed.
                            # The default M value should therefore be irrelevant.
                    child.GDPbb_utils.deactivated_constraints -= newly_activated
                    child.GDPbb_utils.disjuncts_fixed_True.add(child_disjunct)

                    if disjunct in incumbent_model.GDPbb_utils.disjuncts_fixed_True:
                        # If the disjunct was already branched to True from a parent disjunct branching, just pass
                        # through the incumbent value without resolving. The solution should be the same as the parent.
                        total_nodes_counter += 1
                        ordering_tuple = (obj_sign * incumbent_obj_value,
                                          disjunctions_left - 1,
                                          -total_nodes_counter)
                        heapq.heappush(heap, (ordering_tuple, child, result,
                                              incumbent_var_values))
                        new_nodes_counter += 1
                        continue

                    if config.check_sat and satisfiable(
                            child, config.logger) is False:
                        # Problem is not satisfiable. Skip this disjunct.
                        continue

                    obj_value, result, var_values = self.subproblem_solve(
                        child, config)
                    total_nodes_counter += 1
                    ordering_tuple = (obj_sign * obj_value,
                                      disjunctions_left - 1,
                                      -total_nodes_counter)
                    heapq.heappush(heap,
                                   (ordering_tuple, child, result, var_values))
                    new_nodes_counter += 1

                config.logger.info(
                    "Added %s new nodes with %s relaxed disjunctions to the heap. Size now %s."
                    % (new_nodes_counter, disjunctions_left - 1, len(heap)))
Esempio n. 19
0
 def test_simple_sat_model(self):
     m = ConcreteModel()
     m.x = Var()
     m.c = Constraint(expr=1 == m.x)
     m.o = Objective(expr=m.x)
     self.assertTrue(satisfiable(m))
Esempio n. 20
0
 def test_lower_bound_unsat(self):
     m = ConcreteModel()
     m.x = Var(bounds=(0, 5))
     m.c = Constraint(expr=-0.01 == m.x)
     m.o = Objective(expr=m.x)
     self.assertFalse(satisfiable(m))
Esempio n. 21
0
 def test_bounds_sat(self):
     m = ConcreteModel()
     m.x = Var(bounds=(0, 5))
     m.c1 = Constraint(expr=4.99 == m.x)
     m.o = Objective(expr=m.x)
     self.assertTrue(satisfiable(m))
Esempio n. 22
0
 def test_constrained_layout(self):
     exfile = import_file(
         join(exdir, 'constrained_layout', 'cons_layout_model.py'))
     m = exfile.build_constrained_layout_model()
     self.assertTrue(satisfiable(m) is not False)
Esempio n. 23
0
 def test_8PP(self):
     exfile = import_file(
         join(exdir, 'eight_process', 'eight_proc_model.py'))
     m = exfile.build_eight_process_flowsheet()
     self.assertTrue(satisfiable(m) is not False)
Esempio n. 24
0
    def solve(self, model, **kwds):
        config = self.CONFIG(kwds.pop('options', {}))
        config.set_value(kwds)

        # Validate model to be used with gdpbb
        self.validate_model(model)
        # Set solver as an MINLP
        solver = SolverFactory(config.solver)
        solve_data = GDPbbSolveData()
        solve_data.timing = Container()
        solve_data.original_model = model
        solve_data.results = SolverResults()

        old_logger_level = config.logger.getEffectiveLevel()
        with time_code(solve_data.timing, 'total'), \
                restore_logger_level(config.logger), \
                create_utility_block(model, 'GDPbb_utils', solve_data):
            if config.tee and old_logger_level > logging.INFO:
                # If the logger does not already include INFO, include it.
                config.logger.setLevel(logging.INFO)
            config.logger.info(
                "Starting GDPbb version %s using %s as subsolver" %
                (".".join(map(str, self.version())), config.solver))

            # Setup results
            solve_data.results.solver.name = 'GDPbb - %s' % (str(
                config.solver))
            setup_results_object(solve_data, config)
            # Initialize list containing indicator vars for reupdating model after solving
            indicator_list_name = unique_component_name(
                model, "_indicator_list")
            indicator_vars = []
            for disjunction in model.component_data_objects(ctype=Disjunction,
                                                            active=True):
                for disjunct in disjunction.disjuncts:
                    indicator_vars.append(disjunct.indicator_var)
            setattr(model, indicator_list_name, indicator_vars)

            # get objective sense
            objectives = model.component_data_objects(Objective, active=True)
            obj = next(objectives, None)
            obj_sign = 1 if obj.sense == minimize else -1
            solve_data.results.problem.sense = obj.sense
            # clone original model for root node of branch and bound
            root = model.clone()

            # set up lists to keep track of which disjunctions have been covered.

            # this list keeps track of the original disjunctions that were active and are soon to be inactive
            root.GDPbb_utils.unenforced_disjunctions = list(
                disjunction
                for disjunction in root.GDPbb_utils.disjunction_list
                if disjunction.active)

            # this list keeps track of the disjunctions that have been activated by the branch and bound
            root.GDPbb_utils.curr_active_disjunctions = []

            # deactivate all disjunctions in the model
            # self.indicate(root)
            for djn in root.GDPbb_utils.unenforced_disjunctions:
                djn.deactivate()
            # Deactivate all disjuncts in model. To be reactivated when disjunction
            # is reactivated.
            for disj in root.component_data_objects(Disjunct, active=True):
                disj._deactivate_without_fixing_indicator()

            # Satisfiability check would go here

            # solve the root node
            config.logger.info("Solving the root node.")
            obj_value, result, _ = self.subproblem_solve(root, solver, config)

            # initialize minheap for Branch and Bound algorithm
            # Heap structure: (ordering tuple, model)
            # Ordering tuple: (objective value, disjunctions_left, -counter)
            #  - select solutions with lower objective value,
            #    then fewer disjunctions left to explore (depth first),
            #    then more recently encountered (tiebreaker)
            heap = []
            counter = 0
            disjunctions_left = len(root.GDPbb_utils.unenforced_disjunctions)
            heapq.heappush(
                heap, ((obj_sign * obj_value, disjunctions_left, -counter),
                       root, result, root.GDPbb_utils.variable_list))
            # loop to branch through the tree
            while len(heap) > 0:
                # pop best model off of heap
                sort_tup, mdl, mdl_results, vars = heapq.heappop(heap)
                old_obj_val, disjunctions_left, _ = sort_tup
                config.logger.info(
                    "Exploring node with LB %.10g and %s inactive disjunctions."
                    % (old_obj_val, disjunctions_left))

                # if all the originally active disjunctions are active, solve and
                # return solution
                if disjunctions_left == 0:
                    config.logger.info("Model solved.")
                    # Model is solved. Copy over solution values.
                    for orig_var, soln_var in zip(
                            model.GDPbb_utils.variable_list, vars):
                        orig_var.value = soln_var.value

                    solve_data.results.problem.lower_bound = mdl_results.problem.lower_bound
                    solve_data.results.problem.upper_bound = mdl_results.problem.upper_bound
                    solve_data.results.solver.timing = solve_data.timing
                    solve_data.results.solver.termination_condition = mdl_results.solver.termination_condition
                    return solve_data.results

                next_disjunction = mdl.GDPbb_utils.unenforced_disjunctions.pop(
                    0)
                config.logger.info("Activating disjunction %s" %
                                   next_disjunction.name)
                next_disjunction.activate()
                mdl.GDPbb_utils.curr_active_disjunctions.append(
                    next_disjunction)
                djn_left = len(mdl.GDPbb_utils.unenforced_disjunctions)
                for disj in next_disjunction.disjuncts:
                    disj._activate_without_unfixing_indicator()
                    if not disj.indicator_var.fixed:
                        disj.indicator_var = 0  # initially set all indicator vars to zero
                added_disj_counter = 0
                for disj in next_disjunction.disjuncts:
                    if not disj.indicator_var.fixed:
                        disj.indicator_var = 1
                    mnew = mdl.clone()
                    if not disj.indicator_var.fixed:
                        disj.indicator_var = 0

                    # Check feasibility
                    if config.check_sat and satisfiable(
                            mnew, config.logger) is False:
                        # problem is not satisfiable. Skip this disjunct.
                        continue

                    obj_value, result, vars = self.subproblem_solve(
                        mnew, solver, config)
                    counter += 1
                    ordering_tuple = (obj_sign * obj_value, djn_left, -counter)
                    heapq.heappush(heap, (ordering_tuple, mnew, result, vars))
                    added_disj_counter = added_disj_counter + 1
                config.logger.info(
                    "Added %s new nodes with %s relaxed disjunctions to the heap. Size now %s."
                    % (added_disj_counter, djn_left, len(heap)))
Esempio n. 25
0
 def test_strip_pack(self):
     exfile = import_file(
         join(exdir, 'strip_packing', 'strip_packing_concrete.py'))
     m = exfile.build_rect_strip_packing_model()
     self.assertTrue(satisfiable(m))
Esempio n. 26
0
 def test_abs_expressions(self):
     m = ConcreteModel()
     m.x = Var()
     m.c1 = Constraint(expr=-0.001 >= abs(m.x))
     m.o = Objective(expr=m.x)
     self.assertFalse(satisfiable(m))
Esempio n. 27
0
 def test_unhandled_expressions(self):
     m = ConcreteModel()
     m.x = Var()
     m.c1 = Constraint(expr=0 <= log(m.x))
     self.assertTrue(satisfiable(m))
Esempio n. 28
0
 def test_strip_pack(self):
     exfile = import_file(
         join(exdir, 'strip_packing', 'strip_packing_concrete.py'))
     m = exfile.build_rect_strip_packing_model()
     self.assertTrue(satisfiable(m))
Esempio n. 29
0
 def test_simple_sat_model(self):
     m = ConcreteModel()
     m.x = Var()
     m.c = Constraint(expr=1 == m.x)
     m.o = Objective(expr=m.x)
     self.assertTrue(satisfiable(m))
Esempio n. 30
0
 def test_real_domains(self):
     m = ConcreteModel()
     m.x1 = Var(domain=NonNegativeReals)
     m.c1 = Constraint(expr=m.x1 == -1.3)
     self.assertFalse(satisfiable(m))
Esempio n. 31
0
 def test_integer_domains(self):
     m = ConcreteModel()
     m.x1 = Var(domain=PositiveIntegers)
     m.c1 = Constraint(expr=m.x1 == 0.5)
     self.assertFalse(satisfiable(m))
Esempio n. 32
0
 def test_ex_633_trespalacios(self):
     exfile = import_file(join(exdir, 'small_lit', 'ex_633_trespalacios.py'))
     m = exfile.build_simple_nonconvex_gdp()
     self.assertTrue(satisfiable(m) is not False)
Esempio n. 33
0
 def test_unhandled_expressions(self):
     m = ConcreteModel()
     m.x = Var()
     m.c1 = Constraint(expr= 0 <= log(m.x))
     self.assertTrue(satisfiable(m))
Esempio n. 34
0
 def test_lower_bound_unsat(self):
     m = ConcreteModel()
     m.x = Var(bounds=(0, 5))
     m.c = Constraint(expr=-0.01 == m.x)
     m.o = Objective(expr=m.x)
     self.assertFalse(satisfiable(m))
Esempio n. 35
0
 def test_constrained_layout(self):
     exfile = import_file(
         join(exdir, 'constrained_layout', 'cons_layout_model.py'))
     m = exfile.build_constrained_layout_model()
     self.assertTrue(satisfiable(m) is not False)
Esempio n. 36
0
 def test_integer_domains(self):
     m = ConcreteModel()
     m.x1 = Var(domain = PositiveIntegers)
     m.c1 = Constraint(expr = m.x1 == 0.5)
     self.assertFalse(satisfiable(m))
Esempio n. 37
0
 def test_real_domains(self):
     m = ConcreteModel()
     m.x1 = Var(domain = NonNegativeReals)
     m.c1 = Constraint(expr = m.x1 == -1.3)
     self.assertFalse(satisfiable(m))
Esempio n. 38
0
 def test_abs_expressions(self):
     m = ConcreteModel()
     m.x = Var()
     m.c1 = Constraint(expr=-0.001 >= abs(m.x))
     m.o = Objective(expr=m.x)
     self.assertFalse(satisfiable(m))
Esempio n. 39
0
 def test_binary_domains(self):
     m = ConcreteModel()
     m.x1 = Var(domain = Binary)
     m.c1 = Constraint(expr = m.x1 == 2)
     self.assertFalse(satisfiable(m))
Esempio n. 40
0
    def solve(self, model, **kwds):
        config = self.CONFIG(kwds.pop('options', {}))
        config.set_value(kwds)

        # Validate model to be used with gdpbb
        self.validate_model(model)
        # Set solver as an MINLP
        solve_data = GDPbbSolveData()
        solve_data.timing = Container()
        solve_data.original_model = model
        solve_data.results = SolverResults()

        old_logger_level = config.logger.getEffectiveLevel()
        with time_code(solve_data.timing, 'total', is_main_timer=True), \
                restore_logger_level(config.logger), \
                create_utility_block(model, 'GDPbb_utils', solve_data):
            if config.tee and old_logger_level > logging.INFO:
                # If the logger does not already include INFO, include it.
                config.logger.setLevel(logging.INFO)
            config.logger.info(
                "Starting GDPbb version %s using %s as subsolver"
                % (".".join(map(str, self.version())), config.solver)
            )

            # Setup results
            solve_data.results.solver.name = 'GDPbb - %s' % (str(config.solver))
            setup_results_object(solve_data, config)

            # clone original model for root node of branch and bound
            root = solve_data.working_model = solve_data.original_model.clone()

            # get objective sense
            process_objective(solve_data, config)
            objectives = solve_data.original_model.component_data_objects(Objective, active=True)
            obj = next(objectives, None)
            obj_sign = 1 if obj.sense == minimize else -1
            solve_data.results.problem.sense = obj.sense

            # set up lists to keep track of which disjunctions have been covered.

            # this list keeps track of the relaxed disjunctions
            root.GDPbb_utils.unenforced_disjunctions = list(
                disjunction for disjunction in root.GDPbb_utils.disjunction_list if disjunction.active
            )

            root.GDPbb_utils.deactivated_constraints = ComponentSet([
                constr for disjunction in root.GDPbb_utils.unenforced_disjunctions
                for disjunct in disjunction.disjuncts
                for constr in disjunct.component_data_objects(ctype=Constraint, active=True)
                if constr.body.polynomial_degree() not in (1, 0)
            ])
            # Deactivate nonlinear constraints in unenforced disjunctions
            for constr in root.GDPbb_utils.deactivated_constraints:
                constr.deactivate()

            # Add the BigM suffix if it does not already exist. Used later during nonlinear constraint activation.
            if not hasattr(root, 'BigM'):
                root.BigM = Suffix()

            # Pre-screen that none of the disjunctions are already predetermined due to the disjuncts being fixed
            # to True/False values.
            # TODO this should also be done within the loop, but we aren't handling it right now.
            # Should affect efficiency, but not correctness.
            root.GDPbb_utils.disjuncts_fixed_True = ComponentSet()
            # Only find top-level (non-nested) disjunctions
            for disjunction in root.component_data_objects(Disjunction, active=True):
                fixed_true_disjuncts = [disjunct for disjunct in disjunction.disjuncts
                                        if disjunct.indicator_var.fixed
                                        and disjunct.indicator_var.value == 1]
                fixed_false_disjuncts = [disjunct for disjunct in disjunction.disjuncts
                                         if disjunct.indicator_var.fixed
                                         and disjunct.indicator_var.value == 0]
                for disjunct in fixed_false_disjuncts:
                    disjunct.deactivate()
                if len(fixed_false_disjuncts) == len(disjunction.disjuncts) - 1:
                    # all but one disjunct in the disjunction is fixed to False. Remaining one must be true.
                    if not fixed_true_disjuncts:
                        fixed_true_disjuncts = [disjunct for disjunct in disjunction.disjuncts
                                                if disjunct not in fixed_false_disjuncts]
                # Reactivate the fixed-true disjuncts
                for disjunct in fixed_true_disjuncts:
                    newly_activated = ComponentSet()
                    for constr in disjunct.component_data_objects(Constraint):
                        if constr in root.GDPbb_utils.deactivated_constraints:
                            newly_activated.add(constr)
                            constr.activate()
                            # Set the big M value for the constraint
                            root.BigM[constr] = 1
                            # Note: we use a default big M value of 1
                            # because all non-selected disjuncts should be deactivated.
                            # Therefore, none of the big M transformed nonlinear constraints will need to be relaxed.
                            # The default M value should therefore be irrelevant.
                    root.GDPbb_utils.deactivated_constraints -= newly_activated
                    root.GDPbb_utils.disjuncts_fixed_True.add(disjunct)

                if fixed_true_disjuncts:
                    assert disjunction.xor, "GDPbb only handles disjunctions in which one term can be selected. " \
                        "%s violates this assumption." % (disjunction.name, )
                    root.GDPbb_utils.unenforced_disjunctions.remove(disjunction)

            # Check satisfiability
            if config.check_sat and satisfiable(root, config.logger) is False:
                # Problem is not satisfiable. Problem is infeasible.
                obj_value = obj_sign * float('inf')
            else:
                # solve the root node
                config.logger.info("Solving the root node.")
                obj_value, result, var_values = self.subproblem_solve(root, config)

            if obj_sign * obj_value == float('inf'):
                config.logger.info("Model was found to be infeasible at the root node. Elapsed %.2f seconds."
                                   % get_main_elapsed_time(solve_data.timing))
                if solve_data.results.problem.sense == minimize:
                    solve_data.results.problem.lower_bound = float('inf')
                    solve_data.results.problem.upper_bound = None
                else:
                    solve_data.results.problem.lower_bound = None
                    solve_data.results.problem.upper_bound = float('-inf')
                solve_data.results.solver.timing = solve_data.timing
                solve_data.results.solver.iterations = 0
                solve_data.results.solver.termination_condition = tc.infeasible
                return solve_data.results

            # initialize minheap for Branch and Bound algorithm
            # Heap structure: (ordering tuple, model)
            # Ordering tuple: (objective value, disjunctions_left, -total_nodes_counter)
            #  - select solutions with lower objective value,
            #    then fewer disjunctions left to explore (depth first),
            #    then more recently encountered (tiebreaker)
            heap = []
            total_nodes_counter = 0
            disjunctions_left = len(root.GDPbb_utils.unenforced_disjunctions)
            heapq.heappush(
                heap, (
                    (obj_sign * obj_value, disjunctions_left, -total_nodes_counter),
                    root, result, var_values))

            # loop to branch through the tree
            while len(heap) > 0:
                # pop best model off of heap
                sort_tuple, incumbent_model, incumbent_results, incumbent_var_values = heapq.heappop(heap)
                incumbent_obj_value, disjunctions_left, _ = sort_tuple

                config.logger.info("Exploring node with LB %.10g and %s inactive disjunctions." % (
                    incumbent_obj_value, disjunctions_left
                ))

                # if all the originally active disjunctions are active, solve and
                # return solution
                if disjunctions_left == 0:
                    config.logger.info("Model solved.")
                    # Model is solved. Copy over solution values.
                    original_model = solve_data.original_model
                    for orig_var, val in zip(original_model.GDPbb_utils.variable_list, incumbent_var_values):
                        orig_var.value = val

                    solve_data.results.problem.lower_bound = incumbent_results.problem.lower_bound
                    solve_data.results.problem.upper_bound = incumbent_results.problem.upper_bound
                    solve_data.results.solver.timing = solve_data.timing
                    solve_data.results.solver.iterations = total_nodes_counter
                    solve_data.results.solver.termination_condition = incumbent_results.solver.termination_condition
                    return solve_data.results

                # Pick the next disjunction to branch on
                next_disjunction = incumbent_model.GDPbb_utils.unenforced_disjunctions[0]
                config.logger.info("Branching on disjunction %s" % next_disjunction.name)
                assert next_disjunction.xor, "GDPbb only handles disjunctions in which one term can be selected. " \
                    "%s violates this assumption." % (next_disjunction.name, )

                new_nodes_counter = 0

                for i, disjunct in enumerate(next_disjunction.disjuncts):
                    # Create one branch for each of the disjuncts on the disjunction

                    if any(disj.indicator_var.fixed and disj.indicator_var.value == 1
                           for disj in next_disjunction.disjuncts if disj is not disjunct):
                        # If any other disjunct is fixed to 1 and an xor relationship applies,
                        # then this disjunct cannot be activated.
                        continue

                    # Check time limit
                    if get_main_elapsed_time(solve_data.timing) >= config.time_limit:
                        if solve_data.results.problem.sense == minimize:
                            solve_data.results.problem.lower_bound = incumbent_obj_value
                            solve_data.results.problem.upper_bound = float('inf')
                        else:
                            solve_data.results.problem.lower_bound = float('-inf')
                            solve_data.results.problem.upper_bound = incumbent_obj_value
                        config.logger.info(
                            'GDPopt unable to converge bounds '
                            'before time limit of {} seconds. '
                            'Elapsed: {} seconds'
                            .format(config.time_limit, get_main_elapsed_time(solve_data.timing)))
                        config.logger.info(
                            'Final bound values: LB: {}  UB: {}'.
                            format(solve_data.results.problem.lower_bound, solve_data.results.problem.upper_bound))
                        solve_data.results.solver.timing = solve_data.timing
                        solve_data.results.solver.iterations = total_nodes_counter
                        solve_data.results.solver.termination_condition = tc.maxTimeLimit
                        return solve_data.results

                    # Branch on the disjunct
                    child = incumbent_model.clone()
                    # TODO I am leaving the old branching system in place, but there should be
                    # something better, ideally that deals with nested disjunctions as well.
                    disjunction_to_branch = child.GDPbb_utils.unenforced_disjunctions.pop(0)
                    child_disjunct = disjunction_to_branch.disjuncts[i]
                    child_disjunct.indicator_var.fix(1)
                    # Deactivate (and fix to 0) other disjuncts on the disjunction
                    for disj in disjunction_to_branch.disjuncts:
                        if disj is not child_disjunct:
                            disj.deactivate()
                    # Activate nonlinear constraints on the newly fixed child disjunct
                    newly_activated = ComponentSet()
                    for constr in child_disjunct.component_data_objects(Constraint):
                        if constr in child.GDPbb_utils.deactivated_constraints:
                            newly_activated.add(constr)
                            constr.activate()
                            # Set the big M value for the constraint
                            child.BigM[constr] = 1
                            # Note: we use a default big M value of 1
                            # because all non-selected disjuncts should be deactivated.
                            # Therefore, none of the big M transformed nonlinear constraints will need to be relaxed.
                            # The default M value should therefore be irrelevant.
                    child.GDPbb_utils.deactivated_constraints -= newly_activated
                    child.GDPbb_utils.disjuncts_fixed_True.add(child_disjunct)

                    if disjunct in incumbent_model.GDPbb_utils.disjuncts_fixed_True:
                        # If the disjunct was already branched to True from a parent disjunct branching, just pass
                        # through the incumbent value without resolving. The solution should be the same as the parent.
                        total_nodes_counter += 1
                        ordering_tuple = (obj_sign * incumbent_obj_value, disjunctions_left - 1, -total_nodes_counter)
                        heapq.heappush(heap, (ordering_tuple, child, result, incumbent_var_values))
                        new_nodes_counter += 1
                        continue

                    if config.check_sat and satisfiable(child, config.logger) is False:
                        # Problem is not satisfiable. Skip this disjunct.
                        continue

                    obj_value, result, var_values = self.subproblem_solve(child, config)
                    total_nodes_counter += 1
                    ordering_tuple = (obj_sign * obj_value, disjunctions_left - 1, -total_nodes_counter)
                    heapq.heappush(heap, (ordering_tuple, child, result, var_values))
                    new_nodes_counter += 1

                config.logger.info("Added %s new nodes with %s relaxed disjunctions to the heap. Size now %s." % (
                    new_nodes_counter, disjunctions_left - 1, len(heap)))
Esempio n. 41
0
 def test_8PP(self):
     exfile = import_file(
         join(exdir, 'eight_process', 'eight_proc_model.py'))
     m = exfile.build_eight_process_flowsheet()
     self.assertTrue(satisfiable(m) is not False)
Esempio n. 42
0
File: GDPbb.py Progetto: Pyomo/pyomo
    def solve(self, model, **kwds):
        config = self.CONFIG(kwds.pop('options', {}))
        config.set_value(kwds)

        # Validate model to be used with gdpbb
        self.validate_model(model)
        # Set solver as an MINLP
        solver = SolverFactory(config.solver)
        solve_data = GDPbbSolveData()
        solve_data.timing = Container()
        solve_data.original_model = model
        solve_data.results = SolverResults()

        old_logger_level = config.logger.getEffectiveLevel()
        with time_code(solve_data.timing, 'total'), \
                restore_logger_level(config.logger), \
                create_utility_block(model, 'GDPbb_utils', solve_data):
            if config.tee and old_logger_level > logging.INFO:
                # If the logger does not already include INFO, include it.
                config.logger.setLevel(logging.INFO)
            config.logger.info(
                "Starting GDPbb version %s using %s as subsolver"
                % (".".join(map(str, self.version())), config.solver)
            )

            # Setup results
            solve_data.results.solver.name = 'GDPbb - %s' % (str(config.solver))
            setup_results_object(solve_data, config)
            # Initialize list containing indicator vars for reupdating model after solving
            indicator_list_name = unique_component_name(model, "_indicator_list")
            indicator_vars = []
            for disjunction in model.component_data_objects(
                    ctype=Disjunction, active=True):
                for disjunct in disjunction.disjuncts:
                    indicator_vars.append(disjunct.indicator_var)
            setattr(model, indicator_list_name, indicator_vars)

            # get objective sense
            objectives = model.component_data_objects(Objective, active=True)
            obj = next(objectives, None)
            obj_sign = 1 if obj.sense == minimize else -1
            solve_data.results.problem.sense = obj.sense
            # clone original model for root node of branch and bound
            root = model.clone()

            # set up lists to keep track of which disjunctions have been covered.

            # this list keeps track of the original disjunctions that were active and are soon to be inactive
            root.GDPbb_utils.unenforced_disjunctions = list(
                disjunction for disjunction in root.GDPbb_utils.disjunction_list if disjunction.active
            )

            # this list keeps track of the disjunctions that have been activated by the branch and bound
            root.GDPbb_utils.curr_active_disjunctions = []

            # deactivate all disjunctions in the model
            # self.indicate(root)
            for djn in root.GDPbb_utils.unenforced_disjunctions:
                djn.deactivate()
            # Deactivate all disjuncts in model. To be reactivated when disjunction
            # is reactivated.
            for disj in root.component_data_objects(Disjunct, active=True):
                disj._deactivate_without_fixing_indicator()

            # Satisfiability check would go here

            # solve the root node
            config.logger.info("Solving the root node.")
            obj_value, result, _ = self.subproblem_solve(root, solver, config)

            # initialize minheap for Branch and Bound algorithm
            # Heap structure: (ordering tuple, model)
            # Ordering tuple: (objective value, disjunctions_left, -counter)
            #  - select solutions with lower objective value,
            #    then fewer disjunctions left to explore (depth first),
            #    then more recently encountered (tiebreaker)
            heap = []
            counter = 0
            disjunctions_left = len(root.GDPbb_utils.unenforced_disjunctions)
            heapq.heappush(heap,
                           ((obj_sign * obj_value, disjunctions_left, -counter), root,
                            result, root.GDPbb_utils.variable_list))
            # loop to branch through the tree
            while len(heap) > 0:
                # pop best model off of heap
                sort_tup, mdl, mdl_results, vars = heapq.heappop(heap)
                old_obj_val, disjunctions_left, _ = sort_tup
                config.logger.info("Exploring node with LB %.10g and %s inactive disjunctions." % (
                    old_obj_val, disjunctions_left
                ))

                # if all the originally active disjunctions are active, solve and
                # return solution
                if disjunctions_left == 0:
                    config.logger.info("Model solved.")
                    # Model is solved. Copy over solution values.
                    for orig_var, soln_var in zip(model.GDPbb_utils.variable_list, vars):
                        orig_var.value = soln_var.value

                    solve_data.results.problem.lower_bound = mdl_results.problem.lower_bound
                    solve_data.results.problem.upper_bound = mdl_results.problem.upper_bound
                    solve_data.results.solver.timing = solve_data.timing
                    solve_data.results.solver.termination_condition = mdl_results.solver.termination_condition
                    return solve_data.results

                next_disjunction = mdl.GDPbb_utils.unenforced_disjunctions.pop(0)
                config.logger.info("Activating disjunction %s" % next_disjunction.name)
                next_disjunction.activate()
                mdl.GDPbb_utils.curr_active_disjunctions.append(next_disjunction)
                djn_left = len(mdl.GDPbb_utils.unenforced_disjunctions)
                for disj in next_disjunction.disjuncts:
                    disj._activate_without_unfixing_indicator()
                    if not disj.indicator_var.fixed:
                        disj.indicator_var = 0  # initially set all indicator vars to zero
                added_disj_counter = 0
                for disj in next_disjunction.disjuncts:
                    if not disj.indicator_var.fixed:
                        disj.indicator_var = 1
                    mnew = mdl.clone()
                    if not disj.indicator_var.fixed:
                        disj.indicator_var = 0

                    # Check feasibility
                    if config.check_sat and satisfiable(mnew, config.logger) is False:
                        # problem is not satisfiable. Skip this disjunct.
                        continue

                    obj_value, result, vars = self.subproblem_solve(mnew, solver, config)
                    counter += 1
                    ordering_tuple = (obj_sign * obj_value, djn_left, -counter)
                    heapq.heappush(heap, (ordering_tuple, mnew, result, vars))
                    added_disj_counter = added_disj_counter + 1
                config.logger.info("Added %s new nodes with %s relaxed disjunctions to the heap. Size now %s." % (
                    added_disj_counter, djn_left, len(heap)))
Esempio n. 43
0
 def test_ex_633_trespalacios(self):
     exfile = import_file(join(exdir, 'small_lit', 'ex_633_trespalacios.py'))
     m = exfile.build_simple_nonconvex_gdp()
     self.assertTrue(satisfiable(m) is not False)