Exemplo n.º 1
0
 def __add__(self, other):
     """Expression : Sum two expressions.
     """
     if isinstance(other, cvxtypes.constant()) and other.is_zero():
         return self
     self, other = self.broadcast(self, other)
     return cvxtypes.add_expr()([self, other])
Exemplo n.º 2
0
 def __mul__(self, other):
     """The product of two expressions.
     """
     # Multiplying by a constant on the right is handled differently
     # from multiplying by a constant on the left.
     if self.is_constant():
         # TODO HACK catch c.T*x where c is a NumPy 1D array.
         if self.size[0] == other.size[0] and \
            self.size[1] != self.size[0] and \
            isinstance(self, cvxtypes.constant()) and self.is_1D_array:
             self = self.T
         return cvxtypes.mul_expr()(self, other)
     elif other.is_constant():
         # Having the constant on the left is more efficient.
         if self.is_scalar() or other.is_scalar():
             return cvxtypes.mul_expr()(other, self)
         else:
             return cvxtypes.rmul_expr()(self, other)
     # When both expressions are not constant
     # Allow affine * affine but raise DCPError otherwise
     # Cannot multiply two non-constant expressions.
     elif self.is_affine() and other.is_affine():
         warnings.warn("Forming a nonconvex expression (affine)*(affine).")
         return cvxtypes.affine_prod_expr()(self, other)
     else:
         raise DCPError("Cannot multiply %s and %s." % (self.curvature, other.curvature))
Exemplo n.º 3
0
 def __mul__(self, other):
     """The product of two expressions.
     """
     # Multiplying by a constant on the right is handled differently
     # from multiplying by a constant on the left.
     if self.is_constant():
         # TODO HACK catch c.T*x where c is a NumPy 1D array.
         if self.size[0] == other.size[0] and \
            self.size[1] != self.size[0] and \
            isinstance(self, cvxtypes.constant()) and self.is_1D_array:
             self = self.T
         return cvxtypes.mul_expr()(self, other)
     elif other.is_constant():
         # Having the constant on the left is more efficient.
         if self.is_scalar() or other.is_scalar():
             return cvxtypes.mul_expr()(other, self)
         else:
             return cvxtypes.rmul_expr()(self, other)
     # When both expressions are not constant
     # Allow affine * affine but raise DCPError otherwise
     # Cannot multiply two non-constant expressions.
     elif self.is_affine() and other.is_affine():
         warnings.warn("Forming a nonconvex expression (affine)*(affine).")
         return cvxtypes.affine_prod_expr()(self, other)
     else:
         raise DCPError("Cannot multiply %s and %s." % (self.curvature, other.curvature))
Exemplo n.º 4
0
    def __init__(self, x, p, max_denom: int = 1024) -> None:
        self._p_orig = p
        # NB: It is important that the exponent is an attribute, not
        # an argument. This prevents parametrized exponents from being replaced
        # with their logs in Dgp2Dcp.
        self.p = cvxtypes.expression().cast_to_const(p)
        if not (isinstance(self.p, cvxtypes.constant())
                or isinstance(self.p, cvxtypes.parameter())):
            raise ValueError(
                "The exponent `p` must be either a Constant or "
                "a Parameter; received ", type(p))
        self.max_denom = max_denom

        self.p_rational = None
        if isinstance(self.p, cvxtypes.constant()):
            # Compute a rational approximation to p, for DCP (DGP doesn't need
            # an approximation).

            if not isinstance(self._p_orig, cvxtypes.expression()):
                # converting to a CVXPY Constant loses the dtype (eg, int),
                # so fetch the original exponent when possible
                p = self._p_orig
            else:
                p = self.p.value
            # how we convert p to a rational depends on the branch of the function
            if p > 1:
                p, w = pow_high(p, max_denom)
            elif 0 < p < 1:
                p, w = pow_mid(p, max_denom)
            elif p < 0:
                p, w = pow_neg(p, max_denom)

            # note: if, after making the rational approximation, p ends up
            # being 0 or 1, we default to using the 0 or 1 behavior of the
            # atom, which affects the curvature, domain, etc... maybe
            # unexpected behavior to the user if they put in 1.00001?
            if p == 1:
                # in case p is a fraction equivalent to 1
                p = 1
                w = None
            if p == 0:
                p = 0
                w = None

            self.p_rational, self.w = p, w
            self.approx_error = float(abs(self.p_rational - p))
        super(power, self).__init__(x)
Exemplo n.º 5
0
    def is_log_log_constant(self):
        """Is the expression log-log constant, ie, elementwise positive?
        """
        if not self.is_constant():
            return False

        if isinstance(self, (cvxtypes.constant(), cvxtypes.parameter())):
            return self.is_pos()
        else:
            return self.value is not None and np.all(self.value > 0)
Exemplo n.º 6
0
 def cast_to_const(expr):
     """Converts a non-Expression to a Constant.
     """
     if isinstance(expr, list):
         for elem in expr:
             if isinstance(elem, Expression):
                 raise ValueError(
                     "The input must be a single CVXPY Expression, not a list. "
                     "Combine Expressions using atoms such as bmat, hstack, and vstack."
                 )
     return expr if isinstance(expr, Expression) else cvxtypes.constant()(expr)
Exemplo n.º 7
0
    def apply(self, problem):
        """See docstring for MatrixStuffing.apply"""
        inverse_data = InverseData(problem)
        # Form the constraints
        extractor = CoeffExtractor(inverse_data)
        new_obj, new_var, r = self.stuffed_objective(problem, extractor)
        inverse_data.r = r
        # Lower equality and inequality to Zero and NonPos.
        cons = []
        for con in problem.constraints:
            if isinstance(con, Equality):
                con = lower_equality(con)
            elif isinstance(con, Inequality):
                con = lower_inequality(con)
            cons.append(con)

        # Batch expressions together, then split apart.
        expr_list = [arg for c in cons for arg in c.args]
        problem_data_tensor = extractor.affine(expr_list)
        Afull, bfull = canon.get_matrix_and_offset_from_unparameterized_tensor(
            problem_data_tensor, new_var.size)
        if 0 not in Afull.shape and 0 not in bfull.shape:
            Afull = cvxtypes.constant()(Afull)
            bfull = cvxtypes.constant()(np.atleast_1d(bfull))

        new_cons = []
        offset = 0
        for orig_con, con in zip(problem.constraints, cons):
            arg_list = []
            for arg in con.args:
                A = Afull[offset:offset + arg.size, :]
                b = bfull[offset:offset + arg.size]
                arg_list.append(reshape(A @ new_var + b, arg.shape))
                offset += arg.size
            new_constraint = con.copy(arg_list)
            new_cons.append(new_constraint)

        inverse_data.constraints = new_cons
        inverse_data.minimize = type(problem.objective) == Minimize
        new_prob = problems.problem.Problem(Minimize(new_obj), new_cons)
        return new_prob, inverse_data
Exemplo n.º 8
0
 def __radd__(self, other):
     """Expression : Sum two expressions.
     """
     if isinstance(other, cvxtypes.constant()) and other.is_zero():
         return self
     return other + self
Exemplo n.º 9
0
 def cast_to_const(expr):
     """Converts a non-Expression to a Constant.
     """
     return expr if isinstance(expr,
                               Expression) else cvxtypes.constant()(expr)
Exemplo n.º 10
0
    def apply(self, problem):
        """Returns a stuffed problem.

        The returned problem is a minimization problem in which every
        constraint in the problem has affine arguments that are expressed in
        the form A @ x + b.


        Parameters
        ----------
        problem: The problem to stuff; the arguments of every constraint
            must be affine
        constraints: A list of constraints, whose arguments are affine

        Returns
        -------
        Problem
            The stuffed problem
        InverseData
            Data for solution retrieval
        """
        inverse_data = InverseData(problem)
        # Form the constraints
        extractor = CoeffExtractor(inverse_data)
        new_obj, new_var, r = self.stuffed_objective(problem, extractor)
        inverse_data.r = r
        # Lower equality and inequality to Zero and NonPos.
        cons = []
        for con in problem.constraints:
            if isinstance(con, Equality):
                con = lower_equality(con)
            elif isinstance(con, Inequality):
                con = lower_inequality(con)
            elif isinstance(con, SOC) and con.axis == 1:
                con = SOC(con.args[0], con.args[1].T, axis=0,
                          constr_id=con.constr_id)
            cons.append(con)

        # Batch expressions together, then split apart.
        expr_list = [arg for c in cons for arg in c.args]
        Afull, bfull = extractor.affine(expr_list)
        if 0 not in Afull.shape and 0 not in bfull.shape:
            Afull = cvxtypes.constant()(Afull)
            bfull = cvxtypes.constant()(bfull)

        new_cons = []
        offset = 0
        for con in cons:
            arg_list = []
            for arg in con.args:
                A = Afull[offset:offset+arg.size, :]
                b = bfull[offset:offset+arg.size]
                arg_list.append(reshape(A*new_var + b, arg.shape))
                offset += arg.size
            new_cons.append(con.copy(arg_list))
            # Map old constraint id to new constraint id.
            inverse_data.cons_id_map[con.id] = new_cons[-1].id

        inverse_data.minimize = type(problem.objective) == Minimize
        new_prob = problems.problem.Problem(Minimize(new_obj), new_cons)
        return new_prob, inverse_data
Exemplo n.º 11
0
 def cast_to_const(expr):
     """Converts a non-Expression to a Constant.
     """
     return expr if isinstance(expr, Expression) else cvxtypes.constant()(expr)
Exemplo n.º 12
0
def _is_const(p) -> bool:
    return isinstance(p, cvxtypes.constant())