Пример #1
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        x = arg_objs[0]
        w = lu.create_var(size)
        v = lu.create_var(size)
        two = lu.create_const(2, (1, 1))
        # w**2 + 2*v
        obj, constraints = square.graph_implementation([w], size)
        obj = lu.sum_expr([obj, lu.mul_expr(two, v, size)])
        # x <= w + v
        constraints.append(lu.create_leq(x, lu.sum_expr([w, v])))
        # v >= 0
        constraints.append(lu.create_geq(v))
        return (obj, constraints)
Пример #2
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        # min sum_entries(t) + kq
        # s.t. x <= t + q
        #      0 <= t
        x = arg_objs[0]
        k = lu.create_const(data[0], (1, 1))
        q = lu.create_var((1, 1))
        t = lu.create_var(x.size)
        sum_t, constr = sum_entries.graph_implementation([t], (1, 1))
        obj = lu.sum_expr([sum_t, lu.mul_expr(k, q, (1, 1))])
        prom_q = lu.promote(q, x.size)
        constr.append(lu.create_leq(x, lu.sum_expr([t, prom_q])))
        constr.append(lu.create_geq(t))
        return (obj, constr)
Пример #3
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        x = arg_objs[0]
        w = lu.create_var(size)
        v = lu.create_var(size)
        two = lu.create_const(2, (1, 1))
        # w**2 + 2*v
        obj, constraints = square.graph_implementation([w], size)
        obj = lu.sum_expr([obj, lu.mul_expr(two, v, size)])
        # x <= w + v
        constraints.append(lu.create_leq(x, lu.sum_expr([w, v])))
        # v >= 0
        constraints.append(lu.create_geq(v))
        return (obj, constraints)
Пример #4
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        # min sum_entries(t) + kq
        # s.t. x <= t + q
        #      0 <= t
        x = arg_objs[0]
        k = lu.create_const(data[0], (1, 1))
        q = lu.create_var((1, 1))
        t = lu.create_var(x.size)
        sum_t, constr = sum_entries.graph_implementation([t], (1, 1))
        obj = lu.sum_expr([sum_t, lu.mul_expr(k, q, (1, 1))])
        prom_q = lu.promote(q, x.size)
        constr.append( lu.create_leq(x, lu.sum_expr([t, prom_q])) )
        constr.append( lu.create_geq(t) )
        return (obj, constr)
Пример #5
0
 def constraints(self):
     obj, constraints = super(BoolVar, self).canonicalize()
     one = lu.create_const(1, (1, 1))
     constraints += [lu.create_geq(obj),
                     lu.create_leq(obj, one)]
     for i in range(self.size[0]):
         row_sum = lu.sum_expr([self[i, j] for j in range(self.size[0])])
         col_sum = lu.sum_expr([self[j, i] for j in range(self.size[0])])
         constraints += [lu.create_eq(row_sum, one),
                         lu.create_eq(col_sum, one)]
     return constraints
Пример #6
0
 def graph_implementation(arg_objs, size, data=None):
     # min 1-sqrt(2z-z^2)
     # s.t. x>=0, z<=1, z = x+s, s<=0
     x = arg_objs[0]
     z = lu.create_var(size)
     s = lu.create_var(size)
     zeros = lu.create_const(np.mat(np.zeros(size)),size)
     ones = lu.create_const(np.mat(np.ones(size)),size)
     z2, constr_square = power.graph_implementation([z],size, (2, (Fraction(1,2), Fraction(1,2))))
     two_z = lu.sum_expr([z,z])
     sub = lu.sub_expr(two_z, z2)
     sq, constr_sqrt = power.graph_implementation([sub],size, (Fraction(1,2), (Fraction(1,2), Fraction(1,2))))
     obj = lu.sub_expr(ones, sq)
     constr = [lu.create_eq(z, lu.sum_expr([x,s]))]+[lu.create_leq(zeros,x)]+[lu.create_leq(z, ones)]+[lu.create_leq(s,zeros)]+constr_square+constr_sqrt
     return (obj, constr)
Пример #7
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        x = arg_objs[0]
        y = arg_objs[1] # Known to be a scalar.
        v = lu.create_var((1, 1))
        two = lu.create_const(2, (1, 1))
        constraints = [SOC(lu.sum_expr([y, v]),
                           [lu.sub_expr(y, v),
                            lu.mul_expr(two, x, x.size)]),
                       lu.create_geq(y)]
        return (v, constraints)
Пример #8
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        # Promote scalars.
        for idx, arg in enumerate(arg_objs):
            if arg.size != size:
                arg_objs[idx] = lu.promote(arg, size)
        x = arg_objs[0]
        y = arg_objs[1]
        v = lu.create_var(x.size)
        two = lu.create_const(2, (1, 1))
        # SOC(x + y, [y - x, 2*v])
        constraints = [
            SOC_Elemwise(lu.sum_expr([x, y]),
                         [lu.sub_expr(y, x),
                          lu.mul_expr(two, v, v.size)])
        ]
        # 0 <= x, 0 <= y
        constraints += [lu.create_geq(x), lu.create_geq(y)]
        return (v, constraints)
Пример #9
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        x = arg_objs[0]
        t = lu.create_var(size)

        # log(1 + exp(x)) <= t <=> exp(-t) + exp(x - t) <= 1
        obj0, constr0 = exp.graph_implementation([lu.neg_expr(t)], size)
        obj1, constr1 = exp.graph_implementation([lu.sub_expr(x, t)], size)
        lhs = lu.sum_expr([obj0, obj1])
        ones = lu.create_const(np.mat(np.ones(size)), size)
        constr = constr0 + constr1 + [lu.create_leq(lhs, ones)]

        return (t, constr)
Пример #10
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        x = arg_objs[0]
        t = lu.create_var((1, 1))
        promoted_t = lu.promote(t, x.size)
        constraints = [
            lu.create_geq(lu.sum_expr([x, promoted_t])),
            lu.create_leq(x, promoted_t)
        ]
        return (t, constraints)
Пример #11
0
def qol_elemwise(arg_objs, size, data=None):
    """Reduces the atom to an affine expression and list of constraints.

    Parameters
    ----------
    arg_objs : list
        LinExpr for each argument.
    size : tuple
        The size of the resulting expression.
    data :
        Additional data required by the atom.

    Returns
    -------
    tuple
        (LinOp for objective, list of constraints)
    """
    x = arg_objs[0]
    y = arg_objs[1]
    t = lu.create_var(x.size)
    two = lu.create_const(2, (1, 1))
    constraints = [SOC_Elemwise(lu.sum_expr([y, t]),
                                [lu.sub_expr(y, t),
                                 lu.mul_expr(two, x, x.size)]),
                   lu.create_geq(y)]
    return (t, constraints)
Пример #12
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        x = arg_objs[0]
        t = lu.create_var(size)

        # log(1 + exp(x)) <= t <=> exp(-t) + exp(x - t) <= 1
        obj0, constr0 = exp.graph_implementation([lu.neg_expr(t)], size)
        obj1, constr1 = exp.graph_implementation([lu.sub_expr(x, t)], size)
        lhs = lu.sum_expr([obj0, obj1])
        ones = lu.create_const(np.mat(np.ones(size)), size)
        constr = constr0 + constr1 + [lu.create_leq(lhs, ones)]

        return (t, constr)
Пример #13
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        # Promote scalars.
        for idx, arg in enumerate(arg_objs):
            if arg.size != size:
                arg_objs[idx] = lu.promote(arg, size)
        x = arg_objs[0]
        y = arg_objs[1]
        v = lu.create_var(x.size)
        two = lu.create_const(2, (1, 1))
        # SOC(x + y, [y - x, 2*v])
        constraints = [
            SOC_Elemwise(lu.sum_expr([x, y]),
                         [lu.sub_expr(y, x),
                          lu.mul_expr(two, v, v.size)])
        ]
        # 0 <= x, 0 <= y
        constraints += [lu.create_geq(x), lu.create_geq(y)]
        return (v, constraints)
Пример #14
0
def qol_elemwise(arg_objs, size, data=None):
    """Reduces the atom to an affine expression and list of constraints.

    Parameters
    ----------
    arg_objs : list
        LinExpr for each argument.
    size : tuple
        The size of the resulting expression.
    data :
        Additional data required by the atom.

    Returns
    -------
    tuple
        (LinOp for objective, list of constraints)
    """
    x = arg_objs[0]
    y = arg_objs[1]
    t = lu.create_var(x.size)
    two = lu.create_const(2, (1, 1))
    constraints = [
        SOC_Elemwise(
            lu.sum_expr([y, t]),
            [lu.sub_expr(y, t), lu.mul_expr(two, x, x.size)]),
        lu.create_geq(y)
    ]
    return (t, constraints)
Пример #15
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        x = arg_objs[0]
        y = arg_objs[1]
        t = lu.create_var((1, 1))
        constraints = [ExpCone(t, x, y),
                       lu.create_geq(y)] # 0 <= y
        # -t - x + y
        obj = lu.sub_expr(y, lu.sum_expr([x, t]))
        return (obj, constraints)
Пример #16
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        x = arg_objs[0]
        y = arg_objs[1]  # Known to be a scalar.
        v = lu.create_var((1, 1))
        two = lu.create_const(2, (1, 1))
        constraints = [
            SOC(lu.sum_expr([y, v]),
                [lu.sub_expr(y, v),
                 lu.mul_expr(two, x, x.size)]),
            lu.create_geq(y)
        ]
        return (v, constraints)
Пример #17
0
 def constr_func(aff_obj):
     theta = [lu.create_var((1, 1)) for i in range(len(values))]
     convex_objs = []
     for val, theta_var in zip(values, theta):
         val_aff = val.canonical_form[0]
         convex_objs.append(
             lu.mul_expr(val_aff, theta_var, val_aff.size))
     convex_combo = lu.sum_expr(convex_objs)
     one = lu.create_const(1, (1, 1))
     constraints = [
         lu.create_eq(aff_obj, convex_combo),
         lu.create_eq(lu.sum_expr(theta), one)
     ]
     for theta_var in theta:
         constraints.append(lu.create_geq(theta_var))
     return constraints
Пример #18
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        # TODO use log for n != 2.
        v = lu.create_var((1, 1))
        x = arg_objs[0]
        y = arg_objs[1]
        two = lu.create_const(2, (1, 1))
        # SOC(x + y, [y - x, 2*v])
        constraints = [
            SOC(lu.sum_expr([x, y]),
                [lu.sub_expr(y, x),
                 lu.mul_expr(two, v, (1, 1))])
        ]
        # 0 <= x, 0 <= y
        constraints += [lu.create_geq(x), lu.create_geq(y)]
        return (v, constraints)
Пример #19
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        x = arg_objs[0]
        y = arg_objs[1]
        t = lu.create_var((1, 1))
        constraints = [ExpCone(t, x, y),
                       lu.create_geq(y)] # 0 <= y
        # -t - x + y
        obj = lu.sub_expr(y, lu.sum_expr([x, t]))
        return (obj, constraints)
Пример #20
0
def gm(t, x, y):
    length = t.size[0] * t.size[1]
    return SOC_Axis(
        lu.reshape(lu.sum_expr([x, y]), (length, 1)),
        lu.vstack([
            lu.reshape(lu.sub_expr(x, y), (1, length)),
            lu.reshape(lu.mul_expr(two, t, t.size), (1, length))
        ], (2, length)), 0)
Пример #21
0
def gm(t, x, y):
    length = t.size[0]*t.size[1]
    return SOC_Axis(lu.reshape(lu.sum_expr([x, y]), (length, 1)),
                    lu.vstack([
                        lu.reshape(lu.sub_expr(x, y), (1, length)),
                        lu.reshape(lu.mul_expr(two, t, t.size), (1, length))
                        ], (2, length)),
                    0)
Пример #22
0
 def constr_func(aff_obj):
     theta = [lu.create_var((1, 1)) for i in xrange(len(values))]
     convex_objs = []
     for val, theta_var in zip(values, theta):
         val_aff = val.canonical_form[0]
         convex_objs.append(
             lu.mul_expr(val_aff, 
                         theta_var, 
                         val_aff.size)
         )
     convex_combo = lu.sum_expr(convex_objs)
     one = lu.create_const(1, (1, 1))
     constraints = [lu.create_eq(aff_obj, convex_combo),
                    lu.create_eq(lu.sum_expr(theta), one)]
     for theta_var in theta:
         constraints.append(lu.create_geq(theta_var))
     return constraints
Пример #23
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        x = arg_objs[0]
        t = lu.create_var(size)

        # log(1 + exp(x)) <= t <=> exp(-t) + exp(x - t) <= 1
        '''
        obj0, constr0 = exp.graph_implementation([lu.neg_expr(t)], size)
        obj1, constr1 = exp.graph_implementation([lu.sub_expr(x, t)], size)
        lhs = lu.sum_expr([obj0, obj1])
        ones = lu.create_const(np.mat(np.ones(size)), size)
        constr = constr0 + constr1 + [lu.create_leq(lhs, ones)]
        '''
        s = data[0]
        if isinstance(s, Parameter):
            s = lu.create_param(s, (1, 1))
        else: # M is constant.
            s = lu.create_const(s, (1, 1))

        #Wrong sign?
        obj0, constr0 = exp.graph_implementation([lu.neg_expr(t)], size)
        obj1, constr1 = exp.graph_implementation([lu.sub_expr(s, lu.sum_expr([t, x]))], size)
        obj2, constr2 = exp.graph_implementation([lu.sub_expr(lu.neg_expr(s), lu.sum_expr([t, x]))], size)
        obj3, constr3 = exp.graph_implementation([lu.sub_expr(lu.neg_expr(t), lu.mul_expr(2, x, size))], size)

        lhs = lu.sum_expr([obj0, obj1, obj2, obj3])
        ones = lu.create_const(np.mat(np.ones(size)), size)
        constr = constr0 + constr1 + constr2 + constr3 + [lu.create_leq(lhs, ones)]


        return (t, constr)
Пример #24
0
 def test_add_expr(self):
     """Test adding lin expr.
     """
     shape = (5, 4)
     x = create_var(shape)
     y = create_var(shape)
     # Expanding dict.
     add_expr = sum_expr([x, y])
     self.assertEqual(add_expr.shape, shape)
     assert len(add_expr.args) == 2
Пример #25
0
    def graph_implementation(arg_objs, shape, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        minimize n^2 + 2M|s|
        subject to s + n = x

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        shape : tuple
            The shape of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        M = data[0]
        x = arg_objs[0]
        n = lu.create_var(shape)
        s = lu.create_var(shape)
        two = lu.create_const(2, (1, 1))
        if isinstance(M, Parameter):
            M = lu.create_param(M, (1, 1))
        else:  # M is constant.
            M = lu.create_const(M.value, (1, 1))

        # n**2 + 2*M*|s|
        n2, constr_sq = power.graph_implementation(
            [n],
            shape, (2, (Fraction(1, 2), Fraction(1, 2)))
        )
        abs_s, constr_abs = abs.graph_implementation([s], shape)
        M_abs_s = lu.mul_expr(M, abs_s)
        obj = lu.sum_expr([n2, lu.mul_expr(two, M_abs_s)])
        # x == s + n
        constraints = constr_sq + constr_abs
        constraints.append(lu.create_eq(x, lu.sum_expr([n, s])))
        return (obj, constraints)
Пример #26
0
 def graph_implementation(arg_objs, size, data=None):
     # min 1-sqrt(2z-z^2)
     # s.t. x>=0, z<=1, z = x+s, s<=0
     x = arg_objs[0]
     z = lu.create_var(size)
     s = lu.create_var(size)
     zeros = lu.create_const(np.mat(np.zeros(size)), size)
     ones = lu.create_const(np.mat(np.ones(size)), size)
     z2, constr_square = power.graph_implementation(
         [z], size, (2, (Fraction(1, 2), Fraction(1, 2))))
     two_z = lu.sum_expr([z, z])
     sub = lu.sub_expr(two_z, z2)
     sq, constr_sqrt = power.graph_implementation(
         [sub], size, (Fraction(1, 2), (Fraction(1, 2), Fraction(1, 2))))
     obj = lu.sub_expr(ones, sq)
     constr = [lu.create_eq(z, lu.sum_expr([x, s]))] + [
         lu.create_leq(zeros, x)
     ] + [lu.create_leq(z, ones)] + [lu.create_leq(s, zeros)
                                     ] + constr_square + constr_sqrt
     return (obj, constr)
Пример #27
0
    def graph_implementation(arg_objs,size,data=None):
        x = arg_objs[0]
        beta,x0 = data[0],data[1]
        beta_val,x0_val = beta.value,x0.value

        if isinstance(beta,Parameter):
            beta = lu.create_param(beta,(1,1))
        else:
            beta = lu.create_const(beta.value,(1,1))
        if isinstance(x0,Parameter):
            x0 = lu.create_param(x0,(1,1))
        else:
            x0 = lu.create_const(x0.value,(1,1))

        xi,psi = lu.create_var(size),lu.create_var(size)
        one = lu.create_const(1,(1,1))
        one_over_beta = lu.create_const(1/beta_val,(1,1))
        k = np.exp(-beta_val*x0_val)
        k = lu.create_const(k,(1,1))

        # 1/beta * (1 - exp(-beta*(xi+x0)))
        xi_plus_x0 = lu.sum_expr([xi,x0])
        minus_beta_times_xi_plus_x0  = lu.neg_expr(lu.mul_expr(beta,xi_plus_x0,size))
        exp_xi,constr_exp = exp.graph_implementation([minus_beta_times_xi_plus_x0],size)
        minus_exp_minus_etc = lu.neg_expr(exp_xi)
        left_branch = lu.mul_expr(one_over_beta, lu.sum_expr([one,minus_exp_minus_etc]),size)

        # psi*exp(-beta*r0)
        right_branch = lu.mul_expr(k,psi,size)

        obj = lu.sum_expr([left_branch,right_branch])

        #x-x0 == xi + psi, xi >= 0, psi <= 0
        zero = lu.create_const(0,size)
        constraints = constr_exp
        prom_x0 = lu.promote(x0, size)
        constraints.append(lu.create_eq(x,lu.sum_expr([prom_x0,xi,psi])))
        constraints.append(lu.create_geq(xi,zero))
        constraints.append(lu.create_leq(psi,zero))

        return (obj, constraints)
Пример #28
0
 def test_get_vars(self):
     """Test getting vars from an expression.
     """
     shape = (5, 4)
     x = create_var(shape)
     y = create_var(shape)
     A = create_const(np.ones(shape), shape)
     # Expanding dict.
     add_expr = sum_expr([x, y, A])
     vars_ = get_expr_vars(add_expr)
     ref = [(x.data, shape), (y.data, shape)]
     self.assertCountEqual(vars_, ref)
Пример #29
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        minimize n^2 + 2M|s|
        subject to s + n = x

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        M = data
        x = arg_objs[0]
        n = lu.create_var(size)
        s = lu.create_var(size)
        two = lu.create_const(2, (1, 1))
        if isinstance(M, Parameter):
            M = lu.create_param(M, (1, 1))
        else: # M is constant.
            M = lu.create_const(M.value, (1, 1))

        # n**2 + 2*M*|s|
        n2, constr_sq = square.graph_implementation([n], size)
        abs_s, constr_abs = abs.graph_implementation([s], size)
        M_abs_s = lu.mul_expr(M, abs_s, size)
        obj = lu.sum_expr([n2, lu.mul_expr(two, M_abs_s, size)])
        # x == s + n
        constraints = constr_sq + constr_abs
        constraints.append(lu.create_eq(x, lu.sum_expr([n, s])))
        return (obj, constraints)
Пример #30
0
 def test_leq_constr(self):
     """Test creating a less than or equal constraint.
     """
     shape = (5, 5)
     x = create_var(shape)
     y = create_var(shape)
     lh_expr = sum_expr([x, y])
     value = np.ones(shape)
     rh_expr = create_const(value, shape)
     constr = create_leq(lh_expr, rh_expr)
     self.assertEqual(constr.shape, shape)
     vars_ = get_expr_vars(constr.expr)
     ref = [(x.data, shape), (y.data, shape)]
     self.assertCountEqual(vars_, ref)
Пример #31
0
    def canonicalize(self):
        """Returns the graph implementation of the object.

        Marks the top level constraint as the dual_holder,
        so the dual value will be saved to the EqConstraint.

        Returns:
            A tuple of (affine expression, [constraints]).
        """
        obj, constraints = self._expr.canonical_form
        half = lu.create_const(0.5, (1, 1))
        symm = lu.mul_expr(half, lu.sum_expr([obj, lu.transpose(obj)]),
                           obj.size)
        dual_holder = SDP(symm, enforce_sym=False, constr_id=self.id)
        return (None, constraints + [dual_holder])
Пример #32
0
    def canonicalize(self):
        """Returns the graph implementation of the object.

        Marks the top level constraint as the dual_holder,
        so the dual value will be saved to the EqConstraint.

        Returns:
            A tuple of (affine expression, [constraints]).
        """
        obj, constraints = self._expr.canonical_form
        half = lu.create_const(0.5, (1,1))
        symm = lu.mul_expr(half, lu.sum_expr([obj, lu.transpose(obj)]),
                           obj.size)
        dual_holder = SDP(symm, enforce_sym=False, constr_id=self.id)
        return (None, constraints + [dual_holder])
Пример #33
0
 def test_eq_constr(self):
     """Test creating an equality constraint.
     """
     shape = (5, 5)
     x = create_var(shape)
     y = create_var(shape)
     lh_expr = sum_expr([x, y])
     value = np.ones(shape)
     rh_expr = create_const(value, shape)
     constr = create_eq(lh_expr, rh_expr)
     self.assertEqual(constr.shape, shape)
     vars_ = get_expr_vars(constr.expr)
     ref = [(x.data, shape), (y.data, shape)]
     if PY2:
         self.assertItemsEqual(vars_, ref)
     else:
         self.assertCountEqual(vars_, ref)
def format_axis(t, X, axis):
    """Formats all the row/column cones for the solver.

    Parameters
    ----------
        t: The scalar part of the second-order constraint.
        X: A matrix whose rows/columns are each a cone.
        axis: Slice by column 0 or row 1.

    Returns
    -------
    list
        A list of LinLeqConstr that represent all the elementwise cones.
    """
    # Reduce to norms of columns.
    if axis == 1:
        X = lu.transpose(X)
    # Create matrices Tmat, Xmat such that Tmat*t + Xmat*X
    # gives the format for the elementwise cone constraints.
    cone_size = 1 + X.shape[0]
    terms = []
    # Make t_mat
    mat_shape = (cone_size, 1)
    t_mat = sp.coo_matrix(([1.0], ([0], [0])), mat_shape).tocsc()
    t_mat = lu.create_const(t_mat, mat_shape, sparse=True)
    t_vec = t
    if not t.shape:
        # t is scalar
        t_vec = lu.reshape(t, (1, 1))
    else:
        # t is 1D
        t_vec = lu.reshape(t, (1, t.shape[0]))
    mul_shape = (cone_size, t_vec.shape[1])
    terms += [lu.mul_expr(t_mat, t_vec, mul_shape)]
    # Make X_mat
    if len(X.shape) == 1:
        X = lu.reshape(X, (X.shape[0], 1))
    mat_shape = (cone_size, X.shape[0])
    val_arr = (cone_size - 1) * [1.0]
    row_arr = list(range(1, cone_size))
    col_arr = list(range(cone_size - 1))
    X_mat = sp.coo_matrix((val_arr, (row_arr, col_arr)), mat_shape).tocsc()
    X_mat = lu.create_const(X_mat, mat_shape, sparse=True)
    mul_shape = (cone_size, X.shape[1])
    terms += [lu.mul_expr(X_mat, X, mul_shape)]
    return [lu.create_geq(lu.sum_expr(terms))]
Пример #35
0
    def graph_implementation(arg_objs, size, data=None):
        """Sum the linear expressions.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        return (lu.sum_expr(arg_objs), [])
Пример #36
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        x = arg_objs[0]
        ones = lu.create_const(np.mat(np.ones(x.size)), x.size)
        xp1 = lu.sum_expr([x, ones])
        return log.graph_implementation([xp1], size, data)
Пример #37
0
    def graph_implementation(arg_objs, shape, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        shape : tuple
            The shape of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        x = arg_objs[0]
        ones = lu.create_const(np.mat(np.ones(x.shape)), x.shape)
        xp1 = lu.sum_expr([x, ones])
        return log.graph_implementation([xp1], shape, data)
Пример #38
0
    def graph_implementation(arg_objs, size, data=None):
        """Sum the linear expressions.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        for i, arg in enumerate(arg_objs):
            if arg.size != size:
                arg_objs[i] = lu.promote(arg, size)
        return (lu.sum_expr(arg_objs), [])
Пример #39
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        x = arg_objs[0]
        t = lu.create_var((1, 1))
        promoted_t = lu.promote(t, x.size)
        constraints = [lu.create_geq(lu.sum_expr([x, promoted_t])), lu.create_leq(x, promoted_t)]
        return (t, constraints)
Пример #40
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        A = arg_objs[0]
        rows, cols = A.size
        # Create the equivalent problem:
        #   minimize (trace(U) + trace(V))/2
        #   subject to:
        #            [U A; A.T V] is positive semidefinite
        X = lu.create_var((rows + cols, rows + cols))
        # Expand A.T.
        obj, constraints = transpose.graph_implementation([A], (cols, rows))
        # Fix X using the fact that A must be affine by the DCP rules.
        # X[0:rows,rows:rows+cols] == A
        index.block_eq(X, A, constraints, 0, rows, rows, rows + cols)
        # X[rows:rows+cols,0:rows] == A.T
        index.block_eq(X, obj, constraints, rows, rows + cols, 0, rows)
        diag = [
            index.get_index(X, constraints, i, i) for i in range(rows + cols)
        ]
        half = lu.create_const(0.5, (1, 1))
        trace = lu.mul_expr(half, lu.sum_expr(diag), (1, 1))
        # Add SDP constraint.
        return (trace, [SDP(X)] + constraints)
Пример #41
0
def format_axis(t, X, axis):
    """Formats all the row/column cones for the solver.

    Parameters
    ----------
        t: The scalar part of the second-order constraint.
        X: A matrix whose rows/columns are each a cone.
        axis: Slice by column 0 or row 1.

    Returns
    -------
    list
        A list of LinLeqConstr that represent all the elementwise cones.
    """
    # Reduce to norms of columns.
    if axis == 1:
        X = lu.transpose(X)
    # Create matrices Tmat, Xmat such that Tmat*t + Xmat*X
    # gives the format for the elementwise cone constraints.
    num_cones = t.size[0]
    cone_size = 1 + X.size[0]
    terms = []
    # Make t_mat
    mat_size = (cone_size, 1)
    prod_size = (cone_size, t.size[0])
    t_mat = sp.coo_matrix(([1.0], ([0], [0])), mat_size).tocsc()
    t_mat = lu.create_const(t_mat, mat_size, sparse=True)
    terms += [lu.mul_expr(t_mat, lu.transpose(t), prod_size)]
    # Make X_mat
    mat_size = (cone_size, X.size[0])
    prod_size = (cone_size, X.size[1])
    val_arr = (cone_size - 1)*[1.0]
    row_arr = range(1, cone_size)
    col_arr = range(cone_size-1)
    X_mat = sp.coo_matrix((val_arr, (row_arr, col_arr)), mat_size).tocsc()
    X_mat = lu.create_const(X_mat, mat_size, sparse=True)
    terms += [lu.mul_expr(X_mat, X, prod_size)]
    return [lu.create_geq(lu.sum_expr(terms))]
Пример #42
0
    def graph_implementation(arg_objs, size, data=None):
        """Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        A = arg_objs[0]
        rows, cols = A.size
        # Create the equivalent problem:
        #   minimize (trace(U) + trace(V))/2
        #   subject to:
        #            [U A; A.T V] is positive semidefinite
        X = lu.create_var((rows+cols, rows+cols))
        # Expand A.T.
        obj, constraints = transpose.graph_implementation([A], (cols, rows))
        # Fix X using the fact that A must be affine by the DCP rules.
        # X[0:rows,rows:rows+cols] == A
        index.block_eq(X, A, constraints,
                       0, rows, rows, rows+cols)
        # X[rows:rows+cols,0:rows] == A.T
        index.block_eq(X, obj, constraints,
                       rows, rows+cols, 0, rows)
        diag = [index.get_index(X, constraints, i, i) for i in range(rows+cols)]
        half = lu.create_const(0.5, (1, 1))
        trace = lu.mul_expr(half, lu.sum_expr(diag), (1, 1))
        # Add SDP constraint.
        return (trace, [SDP(X)] + constraints)
def format_elemwise(vars_):
    """Formats all the elementwise cones for the solver.

    Parameters
    ----------
    vars_ : list
        A list of the LinOp expressions in the elementwise cones.

    Returns
    -------
    list
        A list of LinLeqConstr that represent all the elementwise cones.
    """
    # Create matrices Ai such that 0 <= A0*x0 + ... + An*xn
    # gives the format for the elementwise cone constraints.
    spacing = len(vars_)
    # Matrix spaces out columns of the LinOp expressions.
    mat_shape = (spacing * vars_[0].shape[0], vars_[0].shape[0])
    terms = []
    for i, var in enumerate(vars_):
        mat = get_spacing_matrix(mat_shape, spacing, i)
        terms.append(lu.mul_expr(mat, var))
    return [lu.create_geq(lu.sum_expr(terms))]
Пример #44
0
    def graph_implementation(self,
                             arg_objs,
                             shape: Tuple[int, ...],
                             data=None) -> Tuple[lo.LinOp, List[Constraint]]:
        """Sum the linear expressions.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        shape : tuple
            The shape of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        for i, arg in enumerate(arg_objs):
            if arg.shape != shape and lu.is_scalar(arg):
                arg_objs[i] = lu.promote(arg, shape)
        return (lu.sum_expr(arg_objs), [])
Пример #45
0
def format_elemwise(vars_):
    """Formats all the elementwise cones for the solver.

    Parameters
    ----------
    vars_ : list
        A list of the LinOp expressions in the elementwise cones.

    Returns
    -------
    list
        A list of LinLeqConstr that represent all the elementwise cones.
    """
    # Create matrices Ai such that 0 <= A0*x0 + ... + An*xn
    # gives the format for the elementwise cone constraints.
    spacing = len(vars_)
    prod_size = (spacing*vars_[0].size[0], vars_[0].size[1])
    # Matrix spaces out columns of the LinOp expressions.
    mat_size = (spacing*vars_[0].size[0], vars_[0].size[0])
    terms = []
    for i, var in enumerate(vars_):
        mat = get_spacing_matrix(mat_size, spacing, i)
        terms.append(lu.mul_expr(mat, var, prod_size))
    return [lu.create_geq(lu.sum_expr(terms))]
Пример #46
0
def gm(t, x, y):
    return SOC_Elemwise(lu.sum_expr([x, y]),
               [lu.sub_expr(x, y),
                lu.mul_expr(two, t, t.size)])
Пример #47
0
    def graph_implementation(arg_objs, size, data=None):
        """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
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        A = arg_objs[0]  # n by n matrix.
        n, _ = A.size
        X = lu.create_var((2 * n, 2 * n))
        Z = lu.create_var((n, n))
        D = lu.create_var((n, n))
        # Require that X is symmetric (which implies
        # A is symmetric).
        # X == X.T
        obj, constraints = transpose.graph_implementation([X], (n, n))
        constraints.append(lu.create_eq(X, obj))
        # Require that X and A are PSD.
        constraints += [SDP(X), SDP(A)]
        # Fix Z as upper triangular, D as diagonal,
        # and diag(D) as diag(Z).
        for i in xrange(n):
            for j in xrange(n):
                if i == j:
                    # D[i, j] == Z[i, j]
                    Dij = index.get_index(D, constraints, i, j)
                    Zij = index.get_index(Z, constraints, i, j)
                    constraints.append(lu.create_eq(Dij, Zij))
                if i != j:
                    # D[i, j] == 0
                    Dij = index.get_index(D, constraints, i, j)
                    constraints.append(lu.create_eq(Dij))
                if i > j:
                    # Z[i, j] == 0
                    Zij = index.get_index(Z, constraints, i, j)
                    constraints.append(lu.create_eq(Zij))
        # Fix X using the fact that A must be affine by the DCP rules.
        # X[0:n, 0:n] == D
        index.block_eq(X, D, constraints, 0, n, 0, n)
        # X[0:n, n:2*n] == Z,
        index.block_eq(X, Z, constraints, 0, n, n, 2 * n)
        # X[n:2*n, n:2*n] == A
        index.block_eq(X, A, constraints, n, 2 * n, n, 2 * n)
        # Add the objective sum(log(D[i, i])
        log_diag = []
        for i in xrange(n):
            Dii = index.get_index(D, constraints, i, i)
            obj, constr = log.graph_implementation([Dii], (1, 1))
            constraints += constr
            log_diag.append(obj)
        obj = lu.sum_expr(log_diag)
        return (obj, constraints)
Пример #48
0
    def graph_implementation(arg_objs, size, data=None):
        r"""Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)

        Notes
        -----

        Implementation notes.

        For general ``p``, the p-norm is equivalent to the following convex inequalities:

        .. math::

            x_i &\leq r_i\\
            -x_i &\leq r_i\\
            r_i &\leq s_i^{1/p} t^{1 - 1/p}\\
            \sum_i s_i &\leq t,

        where :math:`p \geq 1`.

        These inequalities are also correct for :math:`p = +\infty` if we interpret :math:`1/\infty` as :math:`0`.


        Although the inequalities above are correct, for a few special cases, we can represent the p-norm
        more efficiently and with fewer variables and inequalities.

        - For :math:`p = 1`, we use the representation

            .. math::

                x_i &\leq r_i\\
                -x_i &\leq r_i\\
                \sum_i r_i &\leq t

        - For :math:`p = \infty`, we use the representation

            .. math::

                x_i &\leq t\\
                -x_i &\leq t

          Note that we don't need the :math:`s` variables or the sum inequality.

        - For :math:`p = 2`, we use the natural second-order cone representation

            .. math::

                \|x\|_2 \leq t

          Note that we could have used the set of inequalities given above if we wanted an alternate decomposition
          of a large second-order cone into into several smaller inequalities.

        """
        p, w = data
        x = arg_objs[0]
        t = None  # dummy value so linter won't complain about initialization
        if p != 1:
            t = lu.create_var((1, 1))

        if p == 2:
            return t, [SOC(t, [x])]

        if p == np.inf:
            r = lu.promote(t, x.size)
        else:
            r = lu.create_var(x.size)

        constraints = [lu.create_geq(lu.sum_expr([x, r])),
                       lu.create_leq(x, r)]

        if p == 1:
            return lu.sum_entries(r), constraints

        if p == np.inf:
            return t, constraints

        # otherwise do case of general p
        s = lu.create_var(x.size)
        # todo: no need to run gm_constr to form the tree each time. we only need to form the tree once
        constraints += gm_constrs(r, [s, lu.promote(t, x.size)], w)
        constraints += [lu.create_leq(lu.sum_entries(s), t)]
        return t, constraints
Пример #49
0
    def graph_implementation(arg_objs, size, data=None):
        """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
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        A = arg_objs[0]  # n by n matrix.
        n, _ = A.size
        X = lu.create_var((2 * n, 2 * n))
        Z = lu.create_var((n, n))
        D = lu.create_var((n, n))
        # Require that X is symmetric (which implies
        # A is symmetric).
        # X == X.T
        obj, constraints = transpose.graph_implementation([X], (n, n))
        constraints.append(lu.create_eq(X, obj))
        # Require that X and A are PSD.
        constraints += [SDP(X), SDP(A)]
        # Fix Z as upper triangular, D as diagonal,
        # and diag(D) as diag(Z).
        for i in xrange(n):
            for j in xrange(n):
                if i == j:
                    # D[i, j] == Z[i, j]
                    Dij = index.get_index(D, constraints, i, j)
                    Zij = index.get_index(Z, constraints, i, j)
                    constraints.append(lu.create_eq(Dij, Zij))
                if i != j:
                    # D[i, j] == 0
                    Dij = index.get_index(D, constraints, i, j)
                    constraints.append(lu.create_eq(Dij))
                if i > j:
                    # Z[i, j] == 0
                    Zij = index.get_index(Z, constraints, i, j)
                    constraints.append(lu.create_eq(Zij))
        # Fix X using the fact that A must be affine by the DCP rules.
        # X[0:n, 0:n] == D
        index.block_eq(X, D, constraints, 0, n, 0, n)
        # X[0:n, n:2*n] == Z,
        index.block_eq(X, Z, constraints, 0, n, n, 2 * n)
        # X[n:2*n, n:2*n] == A
        index.block_eq(X, A, constraints, n, 2 * n, n, 2 * n)
        # Add the objective sum(log(D[i, i])
        log_diag = []
        for i in xrange(n):
            Dii = index.get_index(D, constraints, i, i)
            obj, constr = log.graph_implementation([Dii], (1, 1))
            constraints += constr
            log_diag.append(obj)
        obj = lu.sum_expr(log_diag)
        return (obj, constraints)
Пример #50
0
    def graph_implementation(arg_objs, size, data=None):
        r"""Reduces the atom to an affine expression and list of constraints.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        size : tuple
            The size of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)

        Notes
        -----

        Implementation notes.

        - For general :math:`p \geq 1`, the inequality :math:`\|x\|_p \leq t`
          is equivalent to the following convex inequalities:

          .. math::

              |x_i| &\leq r_i^{1/p} t^{1 - 1/p}\\
              \sum_i r_i &= t.

          These inequalities happen to also be correct for :math:`p = +\infty`,
          if we interpret :math:`1/\infty` as :math:`0`.

        - For general :math:`0 < p < 1`, the inequality :math:`\|x\|_p \geq t`
          is equivalent to the following convex inequalities:

          .. math::

              r_i &\leq x_i^{p} t^{1 - p}\\
              \sum_i r_i &= t.

        - For general :math:`p < 0`, the inequality :math:`\|x\|_p \geq t`
          is equivalent to the following convex inequalities:

          .. math::

              t &\leq x_i^{-p/(1-p)} r_i^{1/(1 - p)}\\
              \sum_i r_i &= t.




        Although the inequalities above are correct, for a few special cases, we can represent the p-norm
        more efficiently and with fewer variables and inequalities.

        - For :math:`p = 1`, we use the representation

            .. math::

                x_i &\leq r_i\\
                -x_i &\leq r_i\\
                \sum_i r_i &= t

        - For :math:`p = \infty`, we use the representation

            .. math::

                x_i &\leq t\\
                -x_i &\leq t

          Note that we don't need the :math:`r` variable or the sum inequality.

        - For :math:`p = 2`, we use the natural second-order cone representation

            .. math::

                \|x\|_2 \leq t

          Note that we could have used the set of inequalities given above if we wanted an alternate decomposition
          of a large second-order cone into into several smaller inequalities.

        """
        p = data[0]
        x = arg_objs[0]
        t = lu.create_var((1, 1))
        constraints = []

        # first, take care of the special cases of p = 2, inf, and 1
        if p == 2:
            return t, [SOC(t, [x])]

        if p == np.inf:
            t_ = lu.promote(t, x.size)
            return t, [lu.create_leq(x, t_), lu.create_geq(lu.sum_expr([x, t_]))]

        # we need an absolute value constraint for the symmetric convex branches (p >= 1)
        # we alias |x| as x from this point forward to make the code pretty :)
        if p >= 1:
            absx = lu.create_var(x.size)
            constraints += [lu.create_leq(x, absx), lu.create_geq(lu.sum_expr([x, absx]))]
            x = absx

        if p == 1:
            return lu.sum_entries(x), 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 = lu.create_var(x.size)
        t_ = lu.promote(t, x.size)
        constraints += [lu.create_eq(lu.sum_entries(r), t)]

        # make p a fraction so that the input weight to gm_constrs
        # is a nice tuple of fractions.
        p = Fraction(p)
        if p < 0:
            constraints += gm_constrs(t_, [x, r], (-p / (1 - p), 1 / (1 - p)))
        if 0 < p < 1:
            constraints += gm_constrs(r, [x, t_], (p, 1 - p))
        if p > 1:
            constraints += gm_constrs(x, [r, t_], (1 / p, 1 - 1 / p))

        return t, constraints