Example #1
0
    def apply(self, problem):
        """Recursively canonicalize the objective and every constraint.
        """
        constraints = []
        for constr in problem.constraints:
            constraints += self._canonicalize_constraint(constr)
        lazy, real = _get_lazy_and_real_constraints(constraints)
        feas_problem = problems.problem.Problem(Minimize(0), real)
        feas_problem._lazy_constraints = lazy

        objective = problem.objective.expr
        if objective.is_nonneg():
            t = Parameter(nonneg=True)
        elif objective.is_nonpos():
            t = Parameter(nonpos=True)
        else:
            t = Parameter()
        constraints += self._canonicalize_constraint(objective <= t)

        lazy, real = _get_lazy_and_real_constraints(constraints)
        param_problem = problems.problem.Problem(Minimize(0), real)
        param_problem._lazy_constraints = lazy
        param_problem._bisection_data = BisectionData(
            feas_problem, t, *tighten.tighten_fns(objective))
        return param_problem, InverseData(problem)
Example #2
0
    def extract_quadratic_coeffs(self, affine_expr, quad_forms):
        """ Assumes quadratic forms all have variable arguments.
            Affine expressions can be anything.
        """

        # Extract affine data.
        affine_problem = cvxpy.Problem(Minimize(affine_expr), [])
        affine_inverse_data = InverseData(affine_problem)
        affine_id_map = affine_inverse_data.id_map
        affine_var_shapes = affine_inverse_data.var_shapes
        extractor = CoeffExtractor(affine_inverse_data)
        c, b = extractor.affine(affine_problem.objective.expr)

        # Combine affine data with quadforms.
        coeffs = {}
        for var in affine_problem.variables():
            if var.id in quad_forms:
                var_id = var.id
                orig_id = quad_forms[var_id][2].args[0].id
                var_offset = affine_id_map[var_id][0]
                var_size = affine_id_map[var_id][1]
                if quad_forms[var_id][2].P.value is not None:
                    c_part = c[0, var_offset:var_offset +
                               var_size].toarray().flatten()
                    P = quad_forms[var_id][2].P.value
                    if sp.issparse(P):
                        P = P.toarray()
                    P = c_part * P
                else:
                    P = sp.diags(c[0, var_offset:var_offset +
                                   var_size].toarray().flatten())
                if orig_id in coeffs:
                    coeffs[orig_id]['P'] += P
                    coeffs[orig_id]['q'] += np.zeros(P.shape[0])
                else:
                    coeffs[orig_id] = dict()
                    coeffs[orig_id]['P'] = P
                    coeffs[orig_id]['q'] = np.zeros(P.shape[0])
            else:
                var_offset = affine_id_map[var.id][0]
                var_size = np.prod(affine_var_shapes[var.id], dtype=int)
                if var.id in coeffs:
                    coeffs[var.id]['P'] += sp.csr_matrix((var_size, var_size))
                    coeffs[var.id]['q'] += c[0, var_offset:var_offset +
                                             var_size].toarray().flatten()
                else:
                    coeffs[var.id] = dict()
                    coeffs[var.id]['P'] = sp.csr_matrix((var_size, var_size))
                    coeffs[var.id]['q'] = c[0, var_offset:var_offset +
                                            var_size].toarray().flatten()
        return coeffs, b
    def apply(self, problem):
        """Recursively canonicalize the objective and every constraint."""
        inverse_data = InverseData(problem)

        canon_objective, canon_constraints = self.canonicalize_tree(
            problem.objective)

        for constraint in problem.constraints:
            # canon_constr is the constraint rexpressed in terms of
            # its canonicalized arguments, and aux_constr are the constraints
            # generated while canonicalizing the arguments of the original
            # constraint
            canon_constr, aux_constr = self.canonicalize_tree(constraint)
            canon_constraints += aux_constr + [canon_constr]
            inverse_data.cons_id_map.update({constraint.id: canon_constr.id})

        new_problem = problems.problem.Problem(canon_objective,
                                               canon_constraints)
        return new_problem, inverse_data
Example #4
0
    def format_constr(self, problem, constr, exp_cone_order):
        """Extract coefficient and offset vector from constraint.

        Special cases PSD constraints, as SCS expects constraints to be
        imposed on solely the lower triangular part of the variable matrix.
        Moreover, it requires the off-diagonal coefficients to be scaled by
        sqrt(2).
        """
        if isinstance(constr, PSD):
            expr = constr.expr
            triangularized_expr = scaled_lower_tri(expr + expr.T) / 2
            extractor = CoeffExtractor(InverseData(problem))
            A_prime, b_prime = extractor.affine(triangularized_expr)
            # SCS requests constraints to be formatted as
            # Ax + s = b, where s is constrained to reside in some
            # cone. Here, however, we are formatting the constraint
            # as A"x + b" = s = -Ax + b; hence, A = -A", b = b"
            return -1 * A_prime, b_prime
        else:
            return super(SCS, self).format_constr(problem, constr,
                                                  exp_cone_order)
Example #5
0
def psd_coeff_offset(problem, c):
    """
    Returns an array "G" and vector "h" such that the given constraint is
      equivalent to "G * z <=_{PSD} h".

    :param problem: the cvxpy Problem in which "c" arises.
    :param c: a cvxpy Constraint defining a linear matrix inequality
      "B + \sum_j A[j] * z[j] >=_{PSD} 0".
    :return: (G, h) such that "c" holds at "z" iff "G * z <=_{PSD} b"
      (where the PSD cone is reshaped into a subset of R^N with N = dim ** 2).

    Note: It is desirable to change this mosek interface so that PSD constraints
    are represented by a vector in R^N with N = (dim * (dim + 1) / 2). This is
    possible because arguments to a linear matrix inequality are necessarily
    symmetric. For now we use N = dim ** 2, because it simplifies implementation
    and only makes a modest difference in the size of the problem seen by mosek.
    """
    extractor = CoeffExtractor(InverseData(problem))
    A_vec, b_vec = extractor.affine(c.expr)
    G = -A_vec
    h = b_vec
    dim = c.expr.shape[0]
    return G, h, dim
Example #6
0
    def apply(self, problem):
        inverse_data = InverseData(problem)
        real2imag = {
            var.id: lu.get_id()
            for var in problem.variables() if var.is_complex()
        }
        constr_dict = {
            cons.id: lu.get_id()
            for cons in problem.constraints if cons.is_complex()
        }
        real2imag.update(constr_dict)
        inverse_data.real2imag = real2imag

        leaf_map = {}
        real_obj, imag_obj = self.canonicalize_tree(problem.objective,
                                                    inverse_data.real2imag,
                                                    leaf_map)
        assert imag_obj is None

        constrs = []
        for constraint in problem.constraints:
            if type(constraint) == Equality:
                constraint = lower_equality(constraint)
            elif type(constraint) == Inequality:
                constraint = lower_inequality(constraint)
            # real2imag maps variable id to a potential new variable
            # created for the imaginary part.
            real_constrs, imag_constrs = self.canonicalize_tree(
                constraint, inverse_data.real2imag, leaf_map)
            if real_constrs is not None:
                constrs.extend(real_constrs)
            if imag_constrs is not None:
                constrs.extend(imag_constrs)

        new_problem = problems.problem.Problem(real_obj, constrs)
        return new_problem, inverse_data