Exemple #1
0
 def relax_variable(self, problem, variable):
     return Variable(
         variable.name,
         problem.lower_bound(variable),
         problem.upper_bound(variable),
         Domain.REAL,
     )
Exemple #2
0
    def relax_objective(self, problem, objective):
        self._objective_count += 1
        if self._objective_count > 1:
            raise ValueError(
                'Apply LinearRelaxation to multiobjective problem')
        new_variable = Variable('_objvar', None, None, Domain.REAL)
        new_objective_expr = LinearExpression([new_variable], [1.0], 0.0)
        new_objective = Objective(
            objective.name,
            new_objective_expr,
            objective.original_sense,
        )

        under_result = self.relax_expression(problem, objective.root_expr)

        new_cons_expr = SumExpression([
            under_result.expression,
            LinearExpression([new_variable], [-1.0], 0.0),
        ])

        new_cons = Constraint('_obj_{}'.format(objective.name), new_cons_expr,
                              None, 0.0)

        under_result.constraints.append(new_cons)
        return RelaxationResult(new_objective, under_result.constraints)
Exemple #3
0
def variables(draw):
    domain = draw(
        st.sampled_from(
            Domain.REALS,
            Domain.INTEGERS,
            Domain.BINARY,
        ))
    lower_bound = draw(st.one_of(st.none(), st.floats()))
    upper_bound = draw(st.one_of(st.none(), st.floats(min_value=lower_bound)))
    return Variable(lower_bound, upper_bound, domain)
Exemple #4
0
    def _insert_variable(self,
                         expr,
                         problem,
                         relaxed_problem,
                         use_problem_bounds=False):
        assert expr.expression_type == ExpressionType.Variable
        if use_problem_bounds and expr.graph is not None:
            lower_bound = problem.lower_bound(expr)
            upper_bound = problem.upper_bound(expr)
            domain = problem.domain(expr)
        else:
            lower_bound = expr.lower_bound
            upper_bound = expr.upper_bound
            domain = expr.domain

        new_var = Variable(expr.name, lower_bound, upper_bound, domain)
        new_var.reference = expr.reference
        new_var = relaxed_problem.add_variable(new_var)
        self._problem_expr[expr.uid] = new_var
        return new_var
Exemple #5
0
    def _underestimate_bilinear_term(self, problem, term, ctx):
        bilinear_aux_vars = ctx.metadata[BILINEAR_AUX_VAR_META]
        x_expr = term.var1
        y_expr = term.var2

        xy_tuple = self._bilinear_tuple(x_expr, y_expr)
        w = self._get_bilinear_aux_var(problem, ctx, xy_tuple)

        if w is None:
            x_l = problem.lower_bound(x_expr)
            x_u = problem.upper_bound(x_expr)

            y_l = problem.lower_bound(y_expr)
            y_u = problem.upper_bound(y_expr)

            if term.var1 == term.var2:
                assert np.isclose(x_l, y_l) and np.isclose(x_u, y_u)
                w_bounds = Interval(x_l, x_u) ** 2
            else:
                w_bounds = Interval(x_l, x_u) * Interval(y_l, y_u)

            w = Variable(
                self._format_aux_name(term.var1, term.var2),
                w_bounds.lower_bound,
                w_bounds.upper_bound,
                Domain.REAL,
            )

            reference = BilinearTermReference(x_expr, y_expr)

            w.reference = reference
            bilinear_aux_vars[xy_tuple] = w
            constraints = self._generate_envelope_constraints(problem, term, w)
        else:
            constraints = []

        new_expr = LinearExpression([w], [term.coefficient], 0.0)

        return new_expr, constraints
Exemple #6
0
 def test_constraints_must_be_constraints(self):
     v = Variable('v', None, None, None)
     c = Constraint('foo', v, None, None)
     with pytest.raises(ValueError):
         ExpressionRelaxationResult(v, [c, Foo()])
    def relax(self, problem, expr, ctx, **kwargs):
        assert expr.expression_type == ExpressionType.Quadratic

        side = kwargs.pop('side')

        term_graph = nx.Graph()
        term_graph.add_nodes_from(ch.idx for ch in expr.children)
        term_graph.add_edges_from(
            (t.var1.idx, t.var2.idx, {'coefficient': t.coefficient})
            for t in expr.terms
        )

        # Check convexity of each connected subgraph
        convex_exprs = []
        nonconvex_exprs = []
        for connected_component in nx.connected_components(term_graph):
            connected_graph = term_graph.subgraph(connected_component)
            vars1 = []
            vars2 = []
            coefs = []
            for (idx1, idx2) in connected_graph.edges:
                coef = connected_graph.edges[idx1, idx2]['coefficient']
                v1 = problem.variable(idx1)
                v2 = problem.variable(idx2)
                vars1.append(v1)
                vars2.append(v2)
                coefs.append(coef)
            quadratic_expr = QuadraticExpression(vars1, vars2, coefs)
            cvx = self._quadratic_rule.apply(
                quadratic_expr, ctx.convexity, ctx.monotonicity, ctx.bounds
            )
            if cvx.is_convex() and side == RelaxationSide.UNDER:
                convex_exprs.append(quadratic_expr)
            elif cvx.is_convex() and side == RelaxationSide.BOTH:
                convex_exprs.append(quadratic_expr)
            elif cvx.is_concave() and side == RelaxationSide.OVER:
                convex_exprs.append(quadratic_expr)
            else:
                nonconvex_exprs.append(quadratic_expr)

        aux_vars = []
        aux_coefs = []
        constraints = []
        if DISAGGREGATE_VAR_AUX_META not in ctx.metadata:
            ctx.metadata[DISAGGREGATE_VAR_AUX_META] = dict()
        bilinear_aux = ctx.metadata[DISAGGREGATE_VAR_AUX_META]
        for quadratic_expr in convex_exprs:
            if len(quadratic_expr.terms) == 1:
                term = quadratic_expr.terms[0]
                xy_idx = (term.var1.idx, term.var2.idx)
                aux_w = bilinear_aux.get(xy_idx, None)
                if aux_w is not None:
                    aux_vars.append(aux_w)
                    aux_coefs.append(term.coefficient)
                    continue

            quadratic_expr_bounds = \
                self._quadratic_bound_propagation_rule.apply(
                    quadratic_expr, ctx.bounds
                )

            aux_w = Variable(
                '_aux_{}'.format(self._call_count),
                quadratic_expr_bounds.lower_bound,
                quadratic_expr_bounds.upper_bound,
                Domain.REAL,
            )

            if len(quadratic_expr.terms) == 1:
                term = quadratic_expr.terms[0]
                xy_idx = (term.var1.idx, term.var2.idx)
                bilinear_aux[xy_idx] = aux_w

            aux_w.reference = ExpressionReference(quadratic_expr)
            aux_vars.append(aux_w)
            aux_coefs.append(1.0)

            if side == RelaxationSide.UNDER:
                lower_bound = None
                upper_bound = 0.0
            elif side == RelaxationSide.OVER:
                lower_bound = 0.0
                upper_bound = None
            else:
                lower_bound = upper_bound = 0.0

            lower_bound = upper_bound = 0.0

            constraint = Constraint(
                '_disaggregate_aux_{}'.format(self._call_count),
                SumExpression([
                    LinearExpression([aux_w], [-1.0], 0.0),
                    quadratic_expr,
                ]),
                lower_bound,
                upper_bound,
            )
            constraint.metadata['original_side'] = side
            constraints.append(constraint)
            self._call_count += 1

        nonconvex_quadratic_expr = QuadraticExpression(nonconvex_exprs)
        nonconvex_quadratic_under = \
            self._bilinear_underestimator.relax(
                problem, nonconvex_quadratic_expr, ctx, **kwargs
            )
        assert nonconvex_quadratic_under is not None

        aux_vars_expr = LinearExpression(
            aux_vars,
            np.ones_like(aux_vars),
            0.0,
        )

        new_expr = LinearExpression(
            [aux_vars_expr, nonconvex_quadratic_under.expression]
        )

        constraints.extend(nonconvex_quadratic_under.constraints)

        return ExpressionRelaxationResult(new_expr, constraints)
Exemple #8
0
 def relax_constraint(self, problem, constraint):
     if constraint.name != 'cons2':
         return RelaxationResult(constraint)
     w = Variable('aux', None, None, None)
     return RelaxationResult(Constraint('aux_cons2', w, None, None))
 def _make_variable(i):
     return Variable('u_%d' % i, None, None, Domain.REAL)