Beispiel #1
0
def vstack(seq):
    """
    | Stacks objects vertically.

    :param seq: tuple or list of numbers,
                :ref:`scalar objects<scalar_ref>` or
                :ref:`multidimensional objects<multi_ref>`.
    :return: :ref:`array<array_obj>` or 
             :ref:`matrix<matrix_obj>`.
    """

    # Check input
    if (type(seq) is not tuple and type(seq) is not list):
        raise TypeError('Invalid argument')

    # Process input
    new_list = []
    numeric = True
    for x in seq:
        if np.isscalar(x):
            new_list += [matrix(x)]
        elif type(x) is cvxpy_obj:
            new_list += [matrix(x.value)]
        elif type(x).__name__ in SCALAR_OBJS:
            numeric = False
            new_x = cvxpy_array(1, 1)
            new_x[0, 0] = x
            new_list += [new_x]
        elif type(x).__name__ in ARRAY_OBJS:
            numeric = False
            new_list += [x]
        elif type(x) is cvxpy_matrix:
            new_list += [x]
        else:
            raise TypeError('Invalid Input')

    # Input is numeric
    if numeric:
        return np.vstack(new_list)

    # Verify dimensions
    n = new_list[0].shape[1]
    for x in new_list:
        if x.shape[1] != n:
            raise ValueError('Invalid Dimensions')

    # Allocate new array
    m = int(np.sum([x.shape[0] for x in new_list]))
    new_ar = cvxpy_array(m, n)

    # Fill new array
    k = 0
    for x in new_list:
        for i in range(0, x.shape[0], 1):
            for j in range(0, x.shape[1], 1):
                new_ar[i + k, j] = x[i, j]
        k = k + x.shape[0]

    # Return new array
    return new_ar
Beispiel #2
0
def diag(v):
    """
    | Extracts diagonal or constructs a diagonal array.
    
    :param v: number, 
              :ref:`scalar object<scalar_ref>`,
              square or one dimensional 
              :ref:`multidimensional object<multi_ref>`.
    :return: number, 
             :ref:`scalar object<scalar_ref>` or
             :ref:`multidimensional object<multi_ref>`.          
    """

    # Check input
    if (np.isscalar(v) or
        type(v).__name__ in SCALAR_OBJS):
        return v
    elif (type(v) is cvxpy_matrix or
          type(v).__name__ in ARRAY_OBJS):
        if v.shape[1]==1:
            v = v.T
    else:
        raise TypeError('Invalid argument type')

    # Get shape
    (m,n) = v.shape

    # Input is 2D
    if m!=1 and n!=1:
        
        # Must be square
        if m!=n:
            raise ValueError('Invalid dimensions')

        # cvxpy matrix
        if type(v) is cvxpy_matrix:
            return matrix(np.diag(v)).T

        # Object array
        else:
            new_ar = cvxpy_array(m,1)
            for i in range(0,m,1):
                new_ar[i,0] = v[i,i]
            return new_ar

    # Input is 1D
    else:
        
        # cvxpy matrix
        if type(v) is cvxpy_matrix:
            return matrix(np.diagflat(v))

        # Object array
        else:
            new_ar = cvxpy_array(n,n)
            for i in range(0,n,1):
                new_ar[i,i] = v[0,i]
            return new_ar    
Beispiel #3
0
def diag(v):
    """
    | Extracts diagonal or constructs a diagonal array.
    
    :param v: number, 
              :ref:`scalar object<scalar_ref>`,
              square or one dimensional 
              :ref:`multidimensional object<multi_ref>`.
    :return: number, 
             :ref:`scalar object<scalar_ref>` or
             :ref:`multidimensional object<multi_ref>`.          
    """

    # Check input
    if (np.isscalar(v) or type(v).__name__ in SCALAR_OBJS):
        return v
    elif (type(v) is cvxpy_matrix or type(v).__name__ in ARRAY_OBJS):
        if v.shape[1] == 1:
            v = v.T
    else:
        raise TypeError('Invalid argument type')

    # Get shape
    (m, n) = v.shape

    # Input is 2D
    if m != 1 and n != 1:

        # Must be square
        if m != n:
            raise ValueError('Invalid dimensions')

        # cvxpy matrix
        if type(v) is cvxpy_matrix:
            return matrix(np.diag(v)).T

        # Object array
        else:
            new_ar = cvxpy_array(m, 1)
            for i in range(0, m, 1):
                new_ar[i, 0] = v[i, i]
            return new_ar

    # Input is 1D
    else:

        # cvxpy matrix
        if type(v) is cvxpy_matrix:
            return matrix(np.diagflat(v))

        # Object array
        else:
            new_ar = cvxpy_array(n, n)
            for i in range(0, n, 1):
                new_ar[i, i] = v[0, i]
            return new_ar
Beispiel #4
0
def compare(obj1, constraint_type, obj2):
    """
    Compares obj1 with obj2.

    :param obj1: Left hand side obejct.
    :param constraint_type: Keyword (See cvxpy.defs.).
    :param obj2: Right hand side object.
    """

    # Both scalars
    if ((np.isscalar(obj1) or type(obj1).__name__ in SCALAR_OBJS)
            and (np.isscalar(obj2) or type(obj2).__name__ in SCALAR_OBJS)):

        # Upgrade scalars to cvxpy_obj
        if np.isscalar(obj1):
            obj1 = cvxpy_obj(CONSTANT, obj1, str(obj1))
        if np.isscalar(obj2):
            obj2 = cvxpy_obj(CONSTANT, obj2, str(obj2))

        # Construct and return constraint
        return cvxpy_constr(obj1, constraint_type, obj2)

    # Upgrate scalars to arrays
    if ((type(obj1) is cvxpy_matrix or type(obj1).__name__ in ARRAY_OBJS)
            and (np.isscalar(obj2) or type(obj2).__name__ in SCALAR_OBJS)):
        (m, n) = obj1.shape
        new_ar = cvxpy_array(m, n)
        for i in range(0, m, 1):
            for j in range(0, n, 1):
                new_ar[i, j] = obj2
        obj2 = new_ar
    if ((type(obj2) is cvxpy_matrix or type(obj2).__name__ in ARRAY_OBJS)
            and (np.isscalar(obj1) or type(obj1).__name__ in SCALAR_OBJS)):
        (m, n) = obj2.shape
        new_ar = cvxpy_array(m, n)
        for i in range(0, m, 1):
            for j in range(0, n, 1):
                new_ar[i, j] = obj1
        obj1 = new_ar

    # Both arrays
    if ((type(obj1) is cvxpy_matrix or type(obj1).__name__ in ARRAY_OBJS) and
        (type(obj2) is cvxpy_matrix or type(obj2).__name__ in ARRAY_OBJS)):
        constr = []
        if obj1.shape != obj2.shape:
            raise ValueError('Invalid dimensions')
        (m, n) = obj1.shape
        for i in range(0, m, 1):
            for j in range(0, n, 1):
                constr += [compare(obj1[i, j], constraint_type, obj2[i, j])]
        return cvxpy_list(constr)

    # Invalid arguments
    raise TypeError('Objects not comparable')
def compare(obj1,constraint_type,obj2):
    """
    Compares obj1 with obj2.

    :param obj1: Left hand side obejct.
    :param constraint_type: Keyword (See cvxpy.defs.).
    :param obj2: Right hand side object.
    """
    
    # Both scalars 
    if ((np.isscalar(obj1) or type(obj1).__name__ in SCALAR_OBJS) and
        (np.isscalar(obj2) or type(obj2).__name__ in SCALAR_OBJS)):
        
        # Upgrade scalars to cvxpy_obj
        if np.isscalar(obj1):
            obj1 = cvxpy_obj(CONSTANT,obj1,str(obj1))
        if np.isscalar(obj2):
            obj2 = cvxpy_obj(CONSTANT,obj2,str(obj2))

        # Construct and return constraint
        return cvxpy_constr(obj1,constraint_type,obj2)

    # Upgrate scalars to arrays
    if ((type(obj1) is cvxpy_matrix or type(obj1).__name__ in ARRAY_OBJS) and
        (np.isscalar(obj2) or type(obj2).__name__ in SCALAR_OBJS)):
        (m,n) = obj1.shape
        new_ar = cvxpy_array(m,n)
        for i in range(0,m,1):
            for j in range(0,n,1):
                new_ar[i,j] = obj2
        obj2 = new_ar
    if ((type(obj2) is cvxpy_matrix or type(obj2).__name__ in ARRAY_OBJS) and
        (np.isscalar(obj1) or type(obj1).__name__ in SCALAR_OBJS)):
        (m,n) = obj2.shape
        new_ar = cvxpy_array(m,n)
        for i in range(0,m,1):
            for j in range(0,n,1):
                new_ar[i,j] = obj1
        obj1 = new_ar
    
    # Both arrays
    if ((type(obj1) is cvxpy_matrix or type(obj1).__name__ in ARRAY_OBJS) and
        (type(obj2) is cvxpy_matrix or type(obj2).__name__ in ARRAY_OBJS)):
        constr = []
        if obj1.shape != obj2.shape:
            raise ValueError('Invalid dimensions')
        (m,n) = obj1.shape
        for i in range(0,m,1):
            for j in range(0,n,1):
                constr += [compare(obj1[i,j],constraint_type,obj2[i,j])]
        return cvxpy_list(constr)

    # Invalid arguments
    raise TypeError('Objects not comparable')    
Beispiel #6
0
def sqrt(x):
    """
    | :math:`\mbox{sqrt} :
      \mathbb{R}_+^{m \\times n} \\to \mathbb{R}^{m \\times n},
      \ \mbox{sqrt}(X)_{ij} = \sqrt{X_{ij}}`. 
    | Concave and increasing.

    :param x: number, 
              :ref:`scalar object<scalar_ref>` or
              :ref:`multidimensional object<multi_ref>`.
    :return: number, 
             :ref:`tree<tree_obj>`, 
             :ref:`matrix<matrix_obj>` or
             :ref:`array<array_obj>`.
    """

    # Prepare input
    if (np.isscalar(x) or 
        type(x).__name__ in SCALAR_OBJS):
        arg = vstack([x])
    elif (type(x) is cvxpy_matrix or
          type(x).__name__ in ARRAY_OBJS):
        arg = x
    else:
        raise TypeError('Invalid argument')

    # Prepare output
    if type(arg) is cvxpy_matrix:
        output = zeros(arg.shape)
    else:
        output = cvxpy_array(arg.shape[0],arg.shape[1])

    # Construct program
    for i in range(0,arg.shape[0],1):
        for j in range(0,arg.shape[1],1):
            t = variable()
            z = variable()
            v = variable()
            p = program(maximize(t),
                        [belongs(vstack((hstack((1.,t)),
                                         hstack((t,v)))),
                                 semidefinite_cone),
                         greater_equals(z,v)],
                        [z],
                        name='sqrt')
            output[i,j] = p(arg[i,j])

    # Return output
    if output.shape == (1,1):
        return output[0,0]
    else:
        return output
Beispiel #7
0
def log_norm_cdf(x):
    """
    | :math:`\mbox{log\_norm\_cdf} :
      \mathbb{R}^{m \\times n} \\to \mathbb{R}^{m \\times n},
      \ \mbox{log\_norm\_cdf}(X)_{ij} = 
      \mbox{log} \\big(
      \int_{-\infty}^{X_{ij}} \\frac{1}{\sqrt{2\pi}} 
      e^{-\\frac{1}{2}u^2} \mathrm{d}u \\big)`.
    | Concave and increasing.

    :param x: number, 
              :ref:`scalar object<scalar_ref>` or
              :ref:`multidimensional object<multi_ref>`.
    :return: number, 
             :ref:`tree<tree_obj>`, 
             :ref:`matrix<matrix_obj>` or
             :ref:`array<array_obj>`.
    """

    # Prepare input
    if (np.isscalar(x) or type(x).__name__ in SCALAR_OBJS):
        arg = vstack([x])
    elif (type(x) is cvxpy_matrix or type(x).__name__ in ARRAY_OBJS):
        arg = x
    else:
        raise TypeError('Invalid argument')

    # Prepare output
    if type(arg) is cvxpy_matrix:
        output = zeros(arg.shape)
    else:
        output = cvxpy_array(arg.shape[0], arg.shape[1])

    # Construct program
    for i in range(0, arg.shape[0], 1):
        for j in range(0, arg.shape[1], 1):
            t = variable()
            v = variable()
            z = variable()
            p = program(maximize(t), [
                belongs(vstack((v, t)), log_norm_cdf_hypo),
                less_equals(v, z)
            ], [z],
                        name='log_norm_cdf')
            output[i, j] = p(arg[i, j])

    # Return output
    if output.shape == (1, 1):
        return output[0, 0]
    else:
        return output
Beispiel #8
0
def sqrt(x):
    """
    | :math:`\mbox{sqrt} :
      \mathbb{R}_+^{m \\times n} \\to \mathbb{R}^{m \\times n},
      \ \mbox{sqrt}(X)_{ij} = \sqrt{X_{ij}}`. 
    | Concave and increasing.

    :param x: number, 
              :ref:`scalar object<scalar_ref>` or
              :ref:`multidimensional object<multi_ref>`.
    :return: number, 
             :ref:`tree<tree_obj>`, 
             :ref:`matrix<matrix_obj>` or
             :ref:`array<array_obj>`.
    """

    # Prepare input
    if (np.isscalar(x) or type(x).__name__ in SCALAR_OBJS):
        arg = vstack([x])
    elif (type(x) is cvxpy_matrix or type(x).__name__ in ARRAY_OBJS):
        arg = x
    else:
        raise TypeError('Invalid argument')

    # Prepare output
    if type(arg) is cvxpy_matrix:
        output = zeros(arg.shape)
    else:
        output = cvxpy_array(arg.shape[0], arg.shape[1])

    # Construct program
    for i in range(0, arg.shape[0], 1):
        for j in range(0, arg.shape[1], 1):
            t = variable()
            z = variable()
            v = variable()
            p = program(maximize(t), [
                belongs(vstack((hstack((1., t)), hstack(
                    (t, v)))), semidefinite_cone),
                greater_equals(z, v)
            ], [z],
                        name='sqrt')
            output[i, j] = p(arg[i, j])

    # Return output
    if output.shape == (1, 1):
        return output[0, 0]
    else:
        return output
Beispiel #9
0
def dub_step(x):
    #print 'input: ', x
    #print 'input.value: ', x.value
    #
    # Prepare input
    if (np.isscalar(x) or 
        type(x).__name__ in SCALAR_OBJS):
        arg = vstack([x])
    elif (type(x) is cvxpy_matrix or
          type(x).__name__ in ARRAY_OBJS):
        arg = x
    else:
        raise TypeError('Invalid argument')

    # Prepare output
    if type(arg) is cvxpy_matrix:
        output = zeros(arg.shape)
    else:
        output = cvxpy_array(arg.shape[0],arg.shape[1])
    
    # helper parameter
    p =  parameter(name = 'p')
    
    # Construct program
    for i in range(0,arg.shape[0],1):
        for j in range(0,arg.shape[1],1):
            t = variable()
            v = variable()
            p = program(minimize(t),
                        [less_equals(v,t),less_equals(-t,v)],
                        [v],
                        name='abs')
            output[i,j] = p(arg[i,j])
            """
            print 'arg[0,0]: ', arg[0,0]
            print 'arg[0,0].value: ', arg[0,0].value
            if arg[0,0].value >= 0:
              p.value = 1
              output[i,j] = p
            else:
              p.value = -1
              output[i,j] = p
            """
    # Return output
    if output.shape == (1,1):
        return output[0,0]
    else:
        return output
Beispiel #10
0
def abs(x):
    """
    | :math:`\mbox{abs} : 
      \mathbb{R}^{m \\times n} \\to \mathbb{R}^{m \\times n},
      \ \mbox{abs}(X)_{ij} = |X_{ij}|`.
    | Convex.

    :param x: number, 
              :ref:`scalar object<scalar_ref>` or 
              :ref:`multidimensional object<multi_ref>`.
    :return: number, 
             :ref:`tree<tree_obj>`, 
             :ref:`matrix<matrix_obj>` or
             :ref:`array<array_obj>`.
    """

    # Prepare input
    if (np.isscalar(x) or 
        type(x).__name__ in SCALAR_OBJS):
        arg = vstack([x])
    elif (type(x) is cvxpy_matrix or
          type(x).__name__ in ARRAY_OBJS):
        arg = x
    else:
        raise TypeError('Invalid argument')

    # Prepare output
    if type(arg) is cvxpy_matrix:
        output = zeros(arg.shape)
    else:
        output = cvxpy_array(arg.shape[0],arg.shape[1])

    # Construct program
    for i in range(0,arg.shape[0],1):
        for j in range(0,arg.shape[1],1):
            t = variable()
            v = variable()
            p = program(minimize(t),
                        [less_equals(v,t),less_equals(-t,v)],
                        [v],
                        name='abs')
            output[i,j] = p(arg[i,j])

    # Return output
    if output.shape == (1,1):
        return output[0,0]
    else:
        return output
Beispiel #11
0
def dub_step(x):
    #print 'input: ', x
    #print 'input.value: ', x.value
    #
    # Prepare input
    if (np.isscalar(x) or type(x).__name__ in SCALAR_OBJS):
        arg = vstack([x])
    elif (type(x) is cvxpy_matrix or type(x).__name__ in ARRAY_OBJS):
        arg = x
    else:
        raise TypeError('Invalid argument')

    # Prepare output
    if type(arg) is cvxpy_matrix:
        output = zeros(arg.shape)
    else:
        output = cvxpy_array(arg.shape[0], arg.shape[1])

    # helper parameter
    p = parameter(name='p')

    # Construct program
    for i in range(0, arg.shape[0], 1):
        for j in range(0, arg.shape[1], 1):
            t = variable()
            v = variable()
            p = program(
                minimize(t),
                [less_equals(v, t), less_equals(-t, v)], [v],
                name='abs')
            output[i, j] = p(arg[i, j])
            """
            print 'arg[0,0]: ', arg[0,0]
            print 'arg[0,0].value: ', arg[0,0].value
            if arg[0,0].value >= 0:
              p.value = 1
              output[i,j] = p
            else:
              p.value = -1
              output[i,j] = p
            """
    # Return output
    if output.shape == (1, 1):
        return output[0, 0]
    else:
        return output
Beispiel #12
0
def reshape(v, newshape):
    """
    | Reshapes the array to dimensions newshape (see np.reshape)
    | in FORTRAN (column-major) order.
    
    :param v: :ref:`array<array_obj>` or 
              :ref:`matrix<matrix_obj>`.
    :param newshape: tuple with two integers.
    :return: the reshaped variable or matrix,
             :ref:`array<array_obj>` or
             :ref:`matrix<matrix_obj>`.
    """

    # Check input
    if (type(v) is cvxpy_matrix or
          type(v).__name__ in ARRAY_OBJS):
        pass
    else:
        raise TypeError('Invalid argument type')

    if not (hasattr(newshape, '__iter__') and
            len(newshape) == 2):
        raise TypeError('Invalid argument for newshape')

    # Get shape
    (m,n) = v.shape

    # Get new shape
    (mn,nn) = newshape

    if mn*nn != m*n:
        raise ValueError('Output dimension size does not match input dimension')

    # cvxpy matrix
    if type(v) is cvxpy_matrix:
        return matrix(np.reshape(v, newshape, order='F'))
    # Object array
    else:
        new_ar = cvxpy_array(mn,nn)
        for j in range(0,n,1):
            for i in range(0,m,1):
                k = j*m + i
                new_ar[k % mn,k / mn] = v[i,j]
        return new_ar
Beispiel #13
0
def reshape(v, newshape):
    """
    | Reshapes the array to dimensions newshape (see np.reshape)
    | in FORTRAN (column-major) order.
    
    :param v: :ref:`array<array_obj>` or 
              :ref:`matrix<matrix_obj>`.
    :param newshape: tuple with two integers.
    :return: the reshaped variable or matrix,
             :ref:`array<array_obj>` or
             :ref:`matrix<matrix_obj>`.
    """

    # Check input
    if (type(v) is cvxpy_matrix or type(v).__name__ in ARRAY_OBJS):
        pass
    else:
        raise TypeError('Invalid argument type')

    if not (hasattr(newshape, '__iter__') and len(newshape) == 2):
        raise TypeError('Invalid argument for newshape')

    # Get shape
    (m, n) = v.shape

    # Get new shape
    (mn, nn) = newshape

    if mn * nn != m * n:
        raise ValueError(
            'Output dimension size does not match input dimension')

    # cvxpy matrix
    if type(v) is cvxpy_matrix:
        return matrix(np.reshape(v, newshape, order='F'))
    # Object array
    else:
        new_ar = cvxpy_array(mn, nn)
        for j in range(0, n, 1):
            for i in range(0, m, 1):
                k = j * m + i
                new_ar[k % mn, k / mn] = v[i, j]
        return new_ar
Beispiel #14
0
def huber(x,M=1):
    """
    | :math:`\mbox{huber} :
      \mathbb{R}^{m \\times n} \\times \mathbb{R}_{++} \\to
      \mathbb{R}^{m \\times n},
      \ \mbox{huber}(X,M)_{ij} = \\left\{  
      \\begin{array}{ll}
      X_{ij}^2,         & |X_{ij}| \leq M \\\\
      M(2|X_{ij}| - M), & |X_{ij}| > M
      \\end{array} \\right.`.
    | Convex.

    :param x: number, 
             :ref:`scalar object<scalar_ref>` or 
             :ref:`multidimensional object<multi_ref>`. 
    :param M: number.
    :return: number, 
             :ref:`tree<tree_obj>`, 
             :ref:`matrix<matrix_obj>` or 
             :ref:`array<array_obj>`.
    """

    # Prepare input
    if (np.isscalar(x) or 
        type(x).__name__ in SCALAR_OBJS):
        arg = vstack([x])
    elif (type(x) is cvxpy_matrix or 
          type(x).__name__ in ARRAY_OBJS):
        arg = x
    else:
        raise TypeError('Invalid first argument')

    # M must be a positive constant
    if not np.isscalar(M):
        raise TypeError('Invalid second argument')
    if M <= 0:
        raise ValueError('Second argument must be positive')

    # Prepare output
    if type(arg) is cvxpy_matrix:
        output = zeros(arg.shape)
    else:
        output = cvxpy_array(arg.shape[0],arg.shape[1])

    # Construct program
    for i in range(0,arg.shape[0],1):
        for j in range(0,arg.shape[1],1):
            v = variable()
            w = variable()
            z = variable()
            p = program(minimize(2*v+square(w)),
                        [less_equals(abs(z),w+v),
                         greater_equals(v,0),
                         greater_equals(w,0),
                         less_equals(w,1)],
                        [z],
                        name='huber') 
            output[i,j] = (M**2.)*p((1./(M*1.))*arg[i,j])

    # Return output
    if output.shape == (1,1):
        return output[0,0]
    else:
        return output
Beispiel #15
0
    def __mulhandle__(self,other):
        """
        Handles left and right multiply.
        Important: If other is a constant, the multiplication
        tree formed has the constant object as the first child.

        :param other: Other operand.
        """

        # Create operator
        operator = cvxpy_obj(OPERATOR,np.NaN,MULTIPLICATION)

        # Number
        if np.isscalar(other):

            # Multiplication by 0
            if other == 0.0:
                return 0.0

            # Multiplication by 1
            elif other == 1.0:
                return self

            # Distribution over addition
            elif (type(self) is cvxpy_tree and
                  self.item.name == SUMMATION):
                new_children = []
                for child in self.children:
                    new_children += [other*child]
                return cvxpy_tree(self.item,new_children)

            # Associativity
            elif (type(self) is cvxpy_tree and
                  self.item.name == MULTIPLICATION and
                  self.children[0].type == CONSTANT):
                new_object = other*self.children[0]
                if new_object.value == 1.0:
                    return self.children[1]
                else:
                    return cvxpy_tree(self.item,[new_object,
                                                 self.children[1]])

            # Constant times constant
            elif type(self) is cvxpy_obj:
                new_const = cvxpy_obj(CONSTANT,self.value*other,
                                      str(self.value*other))
                return new_const

            # Else
            else:            
                constant = cvxpy_obj(CONSTANT,other,str(other))
                return cvxpy_tree(operator,[constant,self])

        # Matrix
        elif type(other) is cvxpy_matrix:
            (m,n) = other.shape
            new_ar = cvxpy_array(m,n)
            for i in range(0,m,1):
                for j in range(0,n,1):
                    new_ar[i,j] = other[i,j]*self
            return new_ar

        # Sparse matrix
        elif type(other) is cvxpy_spmatrix:
            (m,n) = other.shape
            new_ar = cvxpy_sparray(m,n)
            for i in range(0,m,1):
                rowi_indeces = other.rows[i]
                rowi_values = other.data[i]
                for k in range(0,len(rowi_indeces)):
                    new_ar[i,rowi_indeces[k]] = rowi_values[k]*self 
            return new_ar

        # Scalar param
        elif type(other) is cvxpy_scalar_param:
            return cvxpy_tree(operator,[other,self])

        # Tree
        elif type(other) is cvxpy_tree:
            if not len(self.variables):
                return cvxpy_tree(operator,[self,other])
            elif not len(other.variables):
                return cvxpy_tree(operator,[other,self])
            else:
                return NotImplemented

        # Not implemented
        else:
            return NotImplemented
Beispiel #16
0
def vstack(seq):
    """
    | Stacks objects vertically.

    :param seq: tuple or list of numbers,
                :ref:`scalar objects<scalar_ref>` or
                :ref:`multidimensional objects<multi_ref>`.
    :return: :ref:`array<array_obj>` or 
             :ref:`matrix<matrix_obj>`.
    """

    # Check input
    if (type(seq) is not tuple and
        type(seq) is not list):
        raise TypeError('Invalid argument')

    # Process input
    new_list = []
    numeric = True
    for x in seq:
        if np.isscalar(x):
            new_list += [matrix(x)]
        elif type(x) is cvxpy_obj:
            new_list += [matrix(x.value)]
        elif type(x).__name__ in SCALAR_OBJS:
            numeric = False
            new_x = cvxpy_array(1,1)
            new_x[0,0] = x
            new_list += [new_x]
        elif type(x).__name__ in ARRAY_OBJS:
            numeric = False
            new_list += [x]
        elif type(x) is cvxpy_matrix:
            new_list += [x]
        else:
            raise TypeError('Invalid Input')
        
    # Input is numeric
    if numeric:
        return np.vstack(new_list)

    # Verify dimensions
    n = new_list[0].shape[1]
    for x in new_list:
        if x.shape[1] != n:
            raise ValueError('Invalid Dimensions')
    
    # Allocate new array
    m = int(np.sum([x.shape[0] for x in new_list]))
    new_ar = cvxpy_array(m,n)

    # Fill new array
    k = 0
    for x in new_list:
        for i in range(0,x.shape[0],1):
            for j in range(0,x.shape[1],1):
                new_ar[i+k,j] = x[i,j]
        k = k + x.shape[0]
        
    # Return new array
    return new_ar
Beispiel #17
0
    def __raddsub__(self,other,op):
        """
        Handles right add and right subtract.
        
        :param other: Left hand side.
        :param op: Keyword (See cvxpy.defs)
        """

        # Create operator
        operator = cvxpy_obj(OPERATOR,np.NaN,SUMMATION)

        # Create args to combine
        if (type(self) is cvxpy_tree and
            self.item.name == SUMMATION):
            if op == SUMMATION:
                args = self.children
            else:
                args = [-x for x in self.children]
        else:
            if op == SUMMATION:
                args = [self]
            else:
                args = [-self]

        # Number
        if np.isscalar(other):
            if other == 0.0:
                if op == SUMMATION:
                    return self
                else:
                    return -self
            constant = cvxpy_obj(CONSTANT,other,str(other))
            return cvxpy_tree(operator,[constant]+args)

        # Scalar variable or scalar param
        elif (type(other) is cvxpy_scalar_var or
              type(other) is cvxpy_scalar_param):
            return cvxpy_tree(operator,[other]+args)

        # Tree
        elif type(other) is cvxpy_tree:
            if other.item.name == SUMMATION:
                return cvxpy_tree(operator,other.children+args)
            else:
                return cvxpy_tree(operator,[other]+args)
                
        # Matrix
        elif type(other) is cvxpy_matrix:
            (m,n) = other.shape
            new_ar = cvxpy_array(m,n)
            for i in range(0,m,1):
                for j in range(0,n,1):
                    if op == SUMMATION:
                        new_ar[i,j] = other[i,j]+self
                    else:
                        new_ar[i,j] = other[i,j]-self
            return new_ar

        # Not implemented
        else:
            return NotImplemented
Beispiel #18
0
def power_abs(x, p):
    """
    | :math:`\mbox{power\_abs} :
      \mathbb{R}^{m \\times n} \\times [1,\infty) \\to \mathbb{R}^{m \\times n},
      \ \mbox{power\_abs}(X,p)_{ij} = |X_{ij}|^p`.
    | Convex.

    :param x: number, 
              :ref:`scalar object<scalar_ref>` or
              :ref:`multidimensional object<multi_ref>`.
    :param p: number, greater than or equal to one.
    :return: number, 
             :ref:`tree<tree_obj>`, 
             :ref:`matrix<matrix_obj>` or
             :ref:`array<array_obj>`.
    """

    # Prepare input
    if (np.isscalar(x) or type(x).__name__ in SCALAR_OBJS):
        arg = vstack([x])
    elif (type(x) is cvxpy_matrix or type(x).__name__ in ARRAY_OBJS):
        arg = x
    else:
        raise TypeError('Invalid argument')

    # Check p
    if not (np.isscalar(p)):
        raise TypeError('Invalid argument')
    elif p < 1.:
        raise ValueError('Invalid argument value')

    # Prepare output
    if type(arg) is cvxpy_matrix:
        output = zeros(arg.shape)
    else:
        output = cvxpy_array(arg.shape[0], arg.shape[1])

    # Construct program
    for i in range(0, arg.shape[0], 1):
        for j in range(0, arg.shape[1], 1):
            t = variable()
            v = variable()
            z = variable()
            if p > 1.:
                prog = program(minimize(t), [
                    belongs(vstack((v, t)), power_pos_epi(p)),
                    less_equals(-z, v),
                    less_equals(z, v)
                ], [z],
                               name='power_abs')
            else:
                prog = program(
                    minimize(t),
                    [less_equals(z, t), less_equals(-z, t)], [z],
                    name='power_abs')
            output[i, j] = prog(arg[i, j])

    # Return output
    if output.shape == (1, 1):
        return output[0, 0]
    else:
        return output
Beispiel #19
0
def power_p(x,p):
    """
    | :math:`\mbox{power\_p} :
      \mathbb{R}^{m \\times n} \\times [1,\infty) \\to \mathbb{R}^{m \\times n},
      \ \mbox{power\_p}(X,p)_{ij} = \\left\{  
      \\begin{array}{ll}
      X_{ij}^p, & X_{ij} \geq 0 \\\\
      +\infty,  & X_{ij} < 0.
      \\end{array} \\right.`
    | Convex.

    :param x: number, 
              :ref:`scalar object<scalar_ref>` or
              :ref:`multidimensional object<multi_ref>`.
    :param p: number, greater than or equal to one.
    :return: number, 
             :ref:`tree<tree_obj>`, 
             :ref:`matrix<matrix_obj>` or
             :ref:`array<array_obj>`.
    """

    # Prepare input
    if (np.isscalar(x) or
        type(x).__name__ in SCALAR_OBJS):
        arg = vstack([x])
    elif (type(x) is cvxpy_matrix or
          type(x).__name__ in ARRAY_OBJS):
        arg = x
    else:
        raise TypeError('Invalid argument')

    # Check p
    if not (np.isscalar(p)):
        raise TypeError('Invalid argument')
    elif p < 1.:
        raise ValueError('Invalid argument value')

    # Prepare output
    if type(arg) is cvxpy_matrix:
        output = zeros(arg.shape)
    else:
        output = cvxpy_array(arg.shape[0],arg.shape[1])

    # Construct program
    for i in range(0,arg.shape[0],1):
        for j in range(0,arg.shape[1],1):
            t = variable()
            z = variable()
            if p > 1.:
                prog = program(minimize(t),
                               [belongs(vstack((z,t)),
                                        power_pos_epi(p)),
                                greater_equals(z,0)],
                               [z],
                               name='power_p')
            else:
                prog = program(minimize(t),
                               [less_equals(z,t),
                                greater_equals(z,0)],
                               [z],
                               name='power_p')
            if np.isscalar(arg[i,j]) and arg[i,j] < 0.:
                output[i,j] = np.inf
            else:
                output[i,j] = prog(arg[i,j])
            
    # Return output
    if output.shape == (1,1):
        return output[0,0]
    else:
        return output
Beispiel #20
0
def expand(arg):

    # Constant
    if type(arg) is cvxpy_obj:
        return arg, []

    # Scalar variable
    elif type(arg) is cvxpy_scalar_var:
        return arg, []

    # Summation
    elif (type(arg) is cvxpy_tree and arg.item.type == OPERATOR
          and arg.item.name == SUMMATION):

        # Get item and children
        item = arg.item
        children = arg.children

        # New variale
        v = variable()

        # Expand children
        new_children = []
        new_constr = []
        for child in children:

            # Multiplication
            if (child.type == TREE and child.item.type == OPERATOR
                    and child.item.name == MULTIPLICATION):
                child_var, child_constr = expand(child.children[1])
                new_children += [child.children[0].value * child_var]
                new_constr += child_constr

            # Else
            else:
                child_var, child_constr = expand(child)
                new_children += [child_var]
                new_constr += child_constr

        # Return (Always right side is the new variable)
        new_tree = cvxpy_tree(item, new_children)
        return v, [equals(new_tree, v)] + new_constr

    # Multiplication
    elif (type(arg) is cvxpy_tree and arg.item.type == OPERATOR
          and arg.item.name == MULTIPLICATION):

        # Get item and children
        item = arg.item
        children = arg.children

        # New variable
        v = variable()

        # Apply expand to second operand (first is a constant)
        child_var, child_constr = expand(children[1])

        # Return result (Always right side is the new variable)
        new_tree = cvxpy_tree(item, [children[0], child_var])
        new_eq = [equals(new_tree, v)]
        new_eq += child_constr
        return v, new_eq

    # Function
    elif (type(arg) is cvxpy_tree and arg.item.type == FUNCTION):

        # Get item and children
        item = arg.item
        children = arg.children

        # New varibale
        v = variable()

        # Analyze children
        new_children = []
        new_constr = []
        for child in children:
            child_var, child_constr = expand(child)
            new_children += [child_var]
            new_constr += child_constr

        # Return (Always right side is the new variable)
        new_tree = cvxpy_tree(item, new_children)
        if arg.is_convex():
            new_constr += [less_equals(new_tree, v)]
        else:
            new_constr += [greater_equals(new_tree, v)]
        return v, new_constr

    # Constraint
    elif type(arg) is cvxpy_constr:

        # Not set membership
        if arg.type != BELONGS:

            # Apply expand to left and right side
            obj1, constr_list1 = expand(arg.left)
            obj2, constr_list2 = expand(arg.right)

            # Return new constraints
            new_constr = cvxpy_constr(obj1, arg.type, obj2)
            new_list = [new_constr]
            new_list += constr_list1
            new_list += constr_list2
            return new_list

        # Set membership
        else:
            obj, constr_list = expand(arg.left)
            new_constr = cvxpy_constr(obj, arg.type, arg.right)
            return [new_constr] + constr_list

    # Array
    elif (type(arg) is cvxpy_array or type(arg) is cvxpy_var):
        (m, n) = arg.shape
        new_list = []
        new_ar = cvxpy_array(m, n)
        for i in range(0, m, 1):
            for j in range(0, n, 1):

                # Number: Upgrade
                if np.isscalar(arg[i, j]):
                    new_ar[i, j] = cvxpy_obj(CONSTANT, arg[i, j], str(arg[i,
                                                                          j]))

                # Not a number
                else:
                    obj, constr_list = expand(arg[i, j])
                    new_ar[i, j] = obj
                    new_list += constr_list
        return new_ar, new_list

    # List of constraints
    elif (type(arg) is list or type(arg) is cvxpy_list):
        return reduce(lambda x, y: x + y, list(map(expand, arg)), [])

    # Invalid
    else:
        raise TypeError('Invalid argument')