Beispiel #1
0
def pow_nd_canon(con, args):
    """
    con : PowConeND
        We can extract metadata from this.
        For example, con.alpha and con.axis.
    args : tuple of length two
        W,z = args[0], args[1]
    """
    alpha, axis = con.get_data()
    alpha = alpha.value
    W, z = args
    if axis == 1:
        W = W.T
        alpha = alpha.T
    if W.ndim == 1:
        W = reshape(W, (W.size, 1))
        alpha = np.reshape(alpha, (W.size, 1))
    n, k = W.shape
    if n == 2:
        can_con = PowCone3D(W[0, :], W[1, :], z, alpha[0, :])
    else:
        T = Variable(shape=(n - 2, k))
        x_3d, y_3d, z_3d, alpha_3d = [], [], [], []
        for j in range(k):
            x_3d.append(W[:-1, j])
            y_3d.append(T[:, j])
            y_3d.append(W[n - 1, j])
            z_3d.append(z[j])
            z_3d.append(T[:, j])
            r_nums = alpha[:, j]
            r_dens = np.cumsum(r_nums[::-1])[::-1]
            # ^ equivalent to [np.sum(alpha[i:, j]) for i in range(n)]
            r = r_nums / r_dens
            alpha_3d.append(r[:n - 1])
        x_3d = hstack(x_3d)
        y_3d = hstack(y_3d)
        z_3d = hstack(z_3d)
        alpha_p3d = hstack(alpha_3d)
        # TODO: Ideally we should construct x,y,z,alpha_p3d by
        #   applying suitable sparse matrices to W,z,T, rather
        #   than using the hstack atom. (hstack will probably
        #   result in longer compile times).
        can_con = PowCone3D(x_3d, y_3d, z_3d, alpha_p3d)
    # Return a single PowCone3D constraint defined over all auxiliary
    # variables needed for the reduction to go through.
    # There are no "auxiliary constraints" beyond this one.
    return can_con, []
Beispiel #2
0
def add_canon(expr, args):
    if expr.is_scalar():
        return log_sum_exp(hstack(args)), []

    rows = []
    summands = [promote(s, expr.shape) if s.is_scalar() else s for s in args]
    if len(expr.shape) == 1:
        for i in range(expr.shape[0]):
            row = []
            row.append(
                log_sum_exp(hstack([summand[i] for summand in summands])))
            rows.append(row)
        return reshape(bmat(rows), expr.shape), []
    else:
        for i in range(expr.shape[0]):
            row = []
            for j in range(expr.shape[1]):
                row.append(
                    log_sum_exp(hstack([summand[i, j]
                                        for summand in summands])))
            rows.append(row)
        return reshape(bmat(rows), expr.shape), []
Beispiel #3
0
def quad_over_lin_canon(expr, args):
    # quad_over_lin := sum_{ij} X^2_{ij} / y
    x = args[0]
    y = args[1].flatten()
    # precondition: shape == ()
    t = Variable(1,)
    # (y+t, y-t, 2*x) must lie in the second-order cone,
    # where y+t is the scalar part of the second-order
    # cone constraint.
    constraints = [SOC(
                        t=y+t,
                        X=hstack([y-t, 2*x.flatten()]), axis=0
                        ), y >= 0]
    return t, constraints
Beispiel #4
0
def sum_canon(expr, args):
    X = args[0]
    if expr.axis is None:
        summation = explicit_sum(X)
        canon, _ = add_canon(summation, summation.args)
        return reshape(canon, expr.shape), []

    if expr.axis == 0:
        X = X.T

    rows = []
    for i in range(X.shape[0]):
        summation = explicit_sum(X[i])
        canon, _ = add_canon(summation, summation.args)
        rows.append(canon)
    canon = hstack(rows)
    return reshape(canon, expr.shape), []
Beispiel #5
0
def bmat(block_lists):
    """Constructs a block matrix.

    Takes a list of lists. Each internal list is stacked horizontally.
    The internal lists are stacked vertically.

    Parameters
    ----------
    block_lists : list of lists
        The blocks of the block matrix.

    Return
    ------
    CVXPY expression
        The CVXPY expression representing the block matrix.
    """
    row_blocks = [hstack(*blocks) for blocks in block_lists]
    return vstack(*row_blocks)
def mulexpression_canon(expr, args):
    lhs = args[0]
    rhs = args[1]
    lhs_shape, rhs_shape, _ = mul_shapes_promote(lhs.shape, rhs.shape)
    lhs = reshape(lhs, lhs_shape)
    rhs = reshape(rhs, rhs_shape)
    rows = []
    # TODO(akshayka): Parallelize this for large matrices.
    for i in range(lhs.shape[0]):
        row = []
        for j in range(rhs.shape[1]):
            arr = hstack([lhs[i, k] + rhs[k, j] for k in range(lhs.shape[1])])
            row.append(log_sum_exp(arr))
        rows.append(row)
    mat = bmat(rows)
    if mat.shape != expr.shape:
        mat = reshape(mat, expr.shape)
    return mat, []
Beispiel #7
0
def deep_flatten(x):
    # base cases
    if isinstance(x, Expression):
        if len(x.shape) == 1:
            return x
        else:
            return x.flatten()
    elif isinstance(x, np.ndarray) or isinstance(x, (int, float)):
        x = Expression.cast_to_const(x)
        return x.flatten()
    # recursion
    if isinstance(x, list):
        y = []
        for x0 in x:
            x1 = deep_flatten(x0)
            y.append(x1)
        y = hstack(y)
        return y
    msg = 'The input to deep_flatten must be an Expression, a NumPy array, an int'\
          + ' or float, or a nested list thereof. Received input of type %s' % type(x)
    raise ValueError(msg)
Beispiel #8
0
def prod(expr, axis=None, keepdims: bool = False) -> Prod:
    """Multiply the entries of an expression.

    The semantics of this atom are the same as np.prod.

    This atom is log-log affine, but it is neither convex nor concave.

    Parameters
    ----------
    expr : Expression or list[Expression, Numeric]
        The expression to multiply the entries of, or a list of Expressions
        and numeric types.
    axis : int
        The axis along which to take the product; ignored if `expr` is a list.
    keepdims : bool
        Whether to drop dimensions after taking the product; ignored if `expr`
        is a list.
    """
    if isinstance(expr, list):
        return Prod(hstack(expr))
    else:
        return Prod(expr, axis, keepdims)
Beispiel #9
0
def mixed_norm(X, p=2, q=1):
    """Lp,q norm; :math:` (\sum_k (\sum_l \lvert x_{k,l} \rvert )^q/p)^{1/q}`.

    Parameters
    ----------
    X : Expression or numeric constant
        The matrix to take the l_{p,q} norm of.
    p : int or str, optional
        The type of inner norm.
    q : int or str, optional
        The type of outer norm.

    Returns
    -------
    Expression
        An Expression representing the mixed norm.
    """
    X = Expression.cast_to_const(X)

    # inner norms
    vecnorms = [norm(X[i, :], p) for i in range(X.size[0])]

    # outer norm
    return norm(hstack(*vecnorms), q)
Beispiel #10
0
def mixed_norm(X, p=2, q=1):
    """Lp,q norm; :math:` (\sum_k (\sum_l \lvert x_{k,l} \rvert )^q/p)^{1/q}`.

    Parameters
    ----------
    X : Expression or numeric constant
        The matrix to take the l_{p,q} norm of.
    p : int or str, optional
        The type of inner norm.
    q : int or str, optional
        The type of outer norm.

    Returns
    -------
    Expression
        An Expression representing the mixed norm.
    """
    X = Expression.cast_to_const(X)

    # inner norms
    vecnorms = [norm(X[i, :], p) for i in range(X.size[0])]

    # outer norm
    return norm(hstack(*vecnorms), q)
Beispiel #11
0
def col_norm(X, p=2):

    X = Expression.cast_to_const(X)
    vecnorms = [norm(X[:, i], p) for i in range(X.size[1])]
    return hstack(*vecnorms)
Beispiel #12
0
def col_norm(X, p=2):

    X = Expression.cast_to_const(X)
    vecnorms = [ norm(X[:, i], p) for i in range(X.size[1]) ]
    return hstack(*vecnorms)
Beispiel #13
0
def row_norm(X, p=2):

    X = Expression.cast_to_const(X)
    vecnorms = [ norm(X[i, :], p) for i in range(X.size[0]) ]
    return hstack(*vecnorms).T