Exemplo n.º 1
0
def sum_largest_canon(expr, args):
    x = args[0]
    k = expr.k

    # min sum(t) + kq
    # s.t. x <= t + q
    #      0 <= t
    t = Variable(x.shape)
    q = Variable()
    obj = sum(t) + k * q
    constraints = [x <= t + q, t >= 0]
    return obj, constraints
Exemplo n.º 2
0
def norm1_canon(expr, args):
    x = args[0]
    axis = expr.axis

    # we need an absolute value constraint for the symmetric convex branches
    # (p >= 1)
    constraints = []
    # TODO(akshayka): Express this more naturally (recursively), in terms
    # of the other atoms
    abs_expr = abs(x)
    abs_x, abs_constraints = abs_canon(abs_expr, abs_expr.args)
    constraints += abs_constraints
    return sum(abs_x, axis=axis), constraints
Exemplo n.º 3
0
def log_det_canon(expr, args):
    """Reduces the atom to an affine expression and list of constraints.

    Creates the equivalent problem::

       maximize    sum(log(D[i, i]))
       subject to: D diagonal
                   diag(D) = diag(Z)
                   Z is upper triangular.
                   [D Z; Z.T A] is positive semidefinite

    The problem computes the LDL factorization:

    .. math::

       A = (Z^TD^{-1})D(D^{-1}Z)

    This follows from the inequality:

    .. math::

       \\det(A) >= \\det(D) + \\det([D, Z; Z^T, A])/\\det(D)
               >= \\det(D)

    because (Z^TD^{-1})D(D^{-1}Z) is a feasible D, Z that achieves
    det(A) = det(D) and the objective maximizes det(D).

    Parameters
    ----------
    expr : log_det
    args : list
        The arguments for the expression

    Returns
    -------
    tuple
        (Variable for objective, list of constraints)
    """
    A = args[0]  # n by n matrix.
    n, _ = A.shape
    z = Variable(shape=(n * (n + 1) // 2, ))
    Z = vec_to_upper_tri(z, strict=False)
    d = diag_mat(Z)  # a vector
    D = diag_vec(d)  # a matrix
    X = bmat([[D, Z], [Z.T, A]])
    constraints = [PSD(X)]
    log_expr = log(d)
    obj, constr = log_canon(log_expr, log_expr.args)
    constraints += constr
    return sum(obj), constraints
Exemplo n.º 4
0
    def solve(self):
        self.levered_smile = list(
            filter(lambda g: not math.isnan(g.price),
                   sorted(self.levered_smile, key=lambda g: g.strike)))
        self.unlevered_smile = list(
            filter(lambda g: not math.isnan(g.price),
                   sorted(self.unlevered_smile, key=lambda g: g.strike)))

        lstrikes, ulstrikes = list(map(lambda g: g.strike, self.levered_smile)), \
                              list(map(lambda g: g.strike, self.unlevered_smile))

        lprices, ulprices = list(map(lambda g: g.price, self.levered_smile)),\
                            list(map(lambda g: g.price, self.unlevered_smile))

        lpcts, ulpcts = list(map(lambda strike: (strike - self.levered_spot)/self.levered_spot, lstrikes)), \
                        list(map(lambda strike: (strike - self.unlevered_spot) / self.unlevered_spot, ulstrikes))

        ltheta, ultheta = list(map(lambda g: g.theta, self.levered_smile)),\
                            list(map(lambda g: g.theta, self.unlevered_smile))

        lcontract, ulcontract = cp.Variable(
            len(lstrikes), boolean=True), cp.Variable(len(ulstrikes),
                                                      boolean=True)

        spot_ratio = self.levered_spot / self.unlevered_spot
        self.standardized_lratio = round(self.levered_ratio * spot_ratio)

        max_theta = False
        objective = cx.sum(-self.unlevered_ratio * lcontract * ltheta + self.standardized_lratio * ulcontract * ultheta) \
            if max_theta else cx.sum(self.unlevered_ratio * lcontract * lprices - self.standardized_lratio * ulcontract * ulprices)

        prob = cp.Problem(100 * cp.Maximize(objective), [
            cx.sum(lcontract) == 1,
            cx.sum(ulcontract) == 1,
            cx.sum(self.levered_ratio * ulcontract * ulpcts) <= cx.sum(
                self.unlevered_ratio * lcontract * lpcts),
            cx.sum(self.safety_margin * self.standardized_lratio * ulcontract *
                   ulpcts) <= cx.sum(self.unlevered_ratio * lcontract * lpcts)
        ])

        ans = prob.solve(solver=cp.GLPK_MI)

        return ans, self.levered_smile[ArbSmile.idx(
            lcontract)], self.unlevered_smile[ArbSmile.idx(ulcontract)]
Exemplo n.º 5
0
def pnorm_canon(expr, args):
    x = args[0]
    p = expr.p
    axis = expr.axis
    shape = expr.shape
    t = Variable(shape)

    if p == 2:
        if axis is None:
            assert shape == tuple()
            return t, [SOC(t, vec(x))]
        else:
            return t, [SOC(vec(t), x, axis)]

    # we need an absolute value constraint for the symmetric convex branches
    # (p > 1)
    constraints = []
    if p > 1:
        # TODO(akshayka): Express this more naturally (recursively), in terms
        # of the other atoms
        abs_expr = abs(x)
        abs_x, abs_constraints = abs_canon(abs_expr, abs_expr.args)
        x = abs_x
        constraints += abs_constraints

    # now, we take care of the remaining convex and concave branches
    # to create the rational powers, we need a new variable, r, and
    # the constraint sum(r) == t
    r = Variable(x.shape)
    constraints += [sum(r) == t]

    # todo: no need to run gm_constr to form the tree each time.
    # we only need to form the tree once
    promoted_t = Constant(np.ones(x.shape)) * t
    p = Fraction(p)
    if p < 0:
        constraints += gm_constrs(promoted_t, [x, r],
                                  (-p / (1 - p), 1 / (1 - p)))
    if 0 < p < 1:
        constraints += gm_constrs(r, [x, promoted_t], (p, 1 - p))
    if p > 1:
        constraints += gm_constrs(x, [r, promoted_t], (1 / p, 1 - 1 / p))

    return t, constraints
Exemplo n.º 6
0
def scs_coniclift(x, constraints):
    """
    Return (A, b, K) so that
        {x : x satisfies constraints}
    can be written as
        {x : exists y where A @ [x; y] + b in K}.

    Parameters
    ----------
    x: cvxpy.Variable
    constraints: list of cvxpy.constraints.constraint.Constraint
        Each Constraint object must be DCP-compatible.

    Notes
    -----
    This function DOES NOT work when ``x`` has attributes, like ``PSD=True``,
    ``diag=True``, ``symmetric=True``, etc...
    """
    from cvxpy.problems.problem import Problem
    from cvxpy.problems.objective import Minimize
    from cvxpy.atoms.affine.sum import sum
    prob = Problem(Minimize(sum(x)), constraints)
    # ^ The objective value is only used to make sure that "x"
    # participates in the problem. So, if constraints is an
    # empty list, then the support function is the standard
    # support function for R^n.
    data, chain, invdata = prob.get_problem_data(solver='SCS')
    inv = invdata[-2]
    x_offset = inv.var_offsets[x.id]
    x_indices = np.arange(x_offset, x_offset + x.size)
    A = data['A']
    x_selector = np.zeros(shape=(A.shape[1], ), dtype=bool)
    x_selector[x_indices] = True
    A_x = A[:, x_selector]
    A_other = A[:, ~x_selector]
    A = -sparse.hstack([A_x, A_other])
    b = data['b']
    K = data['dims']
    return A, b, K
Exemplo n.º 7
0
def tv(value, *args):
    """Total variation of a vector, matrix, or list of matrices.

    Uses L1 norm of discrete gradients for vectors and
    L2 norm of discrete gradients for matrices.

    Parameters
    ----------
    value : Expression or numeric constant
        The value to take the total variation of.
    args : Matrix constants/expressions
        Additional matrices extending the third dimension of value.

    Returns
    -------
    Expression
        An Expression representing the total variation.
    """
    value = Expression.cast_to_const(value)
    if value.ndim == 0:
        raise ValueError("tv cannot take a scalar argument.")
    # L1 norm for vectors.
    elif value.ndim == 1:
        return norm(value[1:] - value[0:value.shape[0]-1], 1)
    # L2 norm for matrices.
    else:
        rows, cols = value.shape
        args = map(Expression.cast_to_const, args)
        values = [value] + list(args)
        diffs = []
        for mat in values:
            diffs += [
                mat[0:rows-1, 1:cols] - mat[0:rows-1, 0:cols-1],
                mat[1:rows, 0:cols-1] - mat[0:rows-1, 0:cols-1],
            ]
        length = diffs[0].shape[0]*diffs[1].shape[1]
        stacked = vstack([reshape(diff, (1, length)) for diff in diffs])
        return sum(norm(stacked, p=2, axis=0))
Exemplo n.º 8
0
def log_det_canon(expr, args):
    """Reduces the atom to an affine expression and list of constraints.

    Creates the equivalent problem::

       maximize    sum(log(D[i, i]))
       subject to: D diagonal
                   diag(D) = diag(Z)
                   Z is upper triangular.
                   [D Z; Z.T A] is positive semidefinite

    The problem computes the LDL factorization:

    .. math::

       A = (Z^TD^{-1})D(D^{-1}Z)

    This follows from the inequality:

    .. math::

       \\det(A) >= \\det(D) + \\det([D, Z; Z^T, A])/\\det(D)
               >= \\det(D)

    because (Z^TD^{-1})D(D^{-1}Z) is a feasible D, Z that achieves
    det(A) = det(D) and the objective maximizes det(D).

    Parameters
    ----------
    expr : log_det
    args : list
        The arguments for the expression

    Returns
    -------
    tuple
        (Variable for objective, list of constraints)
    """
    A = args[0]  # n by n matrix.
    n, _ = A.shape
    # Require that X and A are PSD.
    X = Variable((2 * n, 2 * n), PSD=True)
    constraints = [PSD(A)]

    # Fix Z as upper triangular
    # TODO represent Z as upper tri vector.
    Z = Variable((n, n))
    Z_lower_tri = upper_tri(transpose(Z))
    constraints.append(Z_lower_tri == 0)

    # Fix diag(D) = diag(Z): D[i, i] = Z[i, i]
    D = Variable(n)
    constraints.append(D == diag_mat(Z))
    # Fix X using the fact that A must be affine by the DCP rules.
    # X[0:n, 0:n] == D
    constraints.append(X[0:n, 0:n] == diag_vec(D))
    # X[0:n, n:2*n] == Z,
    constraints.append(X[0:n, n:2 * n] == Z)
    # X[n:2*n, n:2*n] == A
    constraints.append(X[n:2 * n, n:2 * n] == A)
    # Add the objective sum(log(D[i, i])
    log_expr = log(D)
    obj, constr = log_canon(log_expr, log_expr.args)
    constraints += constr
    return sum(obj), constraints
Exemplo n.º 9
0
def norm1_canon(expr, args):
    assert len(args) == 1
    tmp = sum(args[0], expr.axis, expr.keepdims)
    return sum_canon(tmp, tmp.args)