Example #1
0
def vstack(t):
    """
    Vertical stack.
    """

    # Verify input type
    new_list = []
    numeric = True
    for x in t:
        if (np.isscalar(x)):
            new_list += [matrix(x)]
        elif (type(x) is cvxpy_obj):
            new_list += [matrix(x.data)]
        elif (type(x).__name__ in SCALAR_OBJS):
            numeric = False
            new_x = cvxpy_expression(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 ValueError('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 expression
    m = 0
    for x in new_list:
        m += x.shape[0]
    new_exp = cvxpy_expression(m, n)

    # Fill new expression
    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_exp[i + k, j] = x[i, j]
        k = k + x.shape[0]

    # Return new expression
    return new_exp
Example #2
0
def vstack(t):
    """
    Vertical stack.
    """

    # Verify input type
    new_list = []
    numeric = True
    for x in t:
        if(np.isscalar(x)):
            new_list += [matrix(x)]
        elif(type(x) is cvxpy_obj):
            new_list += [matrix(x.data)]
        elif(type(x).__name__ in SCALAR_OBJS):
            numeric = False
            new_x = cvxpy_expression(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 ValueError('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 expression
    m = 0
    for x in new_list:
        m += x.shape[0]
    new_exp = cvxpy_expression(m,n)

    # Fill new expression
    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_exp[i+k,j] = x[i,j]
        k = k + x.shape[0]
        
    # Return new expression
    return new_exp
Example #3
0
def diagflat(arg):
    """
    List, row or column vector to diagonal matrix.
    """

    # Argument is a list
    if (type(arg) is list):
        arg = hstack(arg)

    # Argument is a matrix or object array
    elif (type(arg) is cvxpy_matrix or type(arg).__name__ in ARRAY_OBJS):
        (m, n) = arg.shape
        if (m != 1 and n != 1):
            raise ValueError('Argument must be one dimensional')
        elif (n == 1):
            arg = arg.T

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

    # Argument is numeric
    numeric = True
    for i in range(0, arg.shape[1], 1):
        if (not np.isscalar(arg[0, i])):
            numeric = False
    if (numeric):
        return matrix(np.diagflat(arg))

    # Not numeric
    (m, n) = arg.shape
    new_exp = cvxpy_expression(n, n)
    for i in range(0, n, 1):
        new_exp[i, i] = arg[0, i]
    return new_exp
Example #4
0
def compare(obj1, op, obj2):

    # 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, op, 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_exp = cvxpy_expression(m, n)
        for i in range(0, m, 1):
            for j in range(0, n, 1):
                new_exp[i, j] = obj2
        obj2 = new_exp
    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_exp = cvxpy_expression(m, n)
        for i in range(0, m, 1):
            for j in range(0, n, 1):
                new_exp[i, j] = obj1
        obj1 = new_exp

    # 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], op, obj2[i, j])]
        return cvxpy_list(constr)

    # Invalid arguments
    raise ValueError('Objects not comparable')
Example #5
0
def compare(obj1,op,obj2):
    
    # 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,op,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_exp = cvxpy_expression(m,n)
        for i in range(0,m,1):
            for j in range(0,n,1):
                new_exp[i,j] = obj2
        obj2 = new_exp
    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_exp = cvxpy_expression(m,n)
        for i in range(0,m,1):
            for j in range(0,n,1):
                new_exp[i,j] = obj1
        obj1 = new_exp
    
    # 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],op,obj2[i,j])]
        return cvxpy_list(constr)

    # Invalid arguments
    raise ValueError('Objects not comparable')    
Example #6
0
    def __call__(self,*arg):

        # Check number of arguments
        if(len(arg) != 1):
            raise ValueError('Invalid number of arguments')
        
        # Extract argument
        if(type(arg[0]) is list):
            x = arg[0][0]
        else:
            x = arg[0]

        # Process
        if(type(x).__name__ in SCALAR_OBJS):
            return cvxpy_tree(self,[x])
        elif(type(x).__name__ in ARRAY_OBJS):
            (m,n) = x.shape
            new_exp = cvxpy_expression(m,n)
            for i in range(0,m,1):
                for j in range(0,n,1):
                    new_exp[i,j] = self(x[i,j])
            return new_exp
        else:
            return np.square(x)
Example #7
0
def diag(arg):
    """
    Extract the diagonal from square array-like object.
    """

    # Check size
    (m, n) = arg.shape
    if (m != n):
        raise ValueError('Invalid dimensions')

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

    # Object array
    elif (type(arg).__name__ in ARRAY_OBJS):
        new_exp = cvxpy_expression(m, 1)
        for i in range(0, m, 1):
            new_exp[i, 0] = arg[i, i]
        return new_exp

    # Error
    else:
        raise ValueError('Invalid argument type')
Example #8
0
    def __call__(self, *arg):

        # Check number of arguments
        if (len(arg) != 1):
            raise ValueError('Invalid number of arguments')

        # Extract argument
        if (type(arg[0]) is list):
            x = arg[0][0]
        else:
            x = arg[0]

        # Process
        if (type(x).__name__ in SCALAR_OBJS):
            return cvxpy_tree(self, [x])
        elif (type(x).__name__ in ARRAY_OBJS):
            (m, n) = x.shape
            new_exp = cvxpy_expression(m, n)
            for i in range(0, m, 1):
                for j in range(0, n, 1):
                    new_exp[i, j] = self(x[i, j])
            return new_exp
        else:
            return np.square(x)
Example #9
0
def diagflat(arg):
    """
    List, row or column vector to diagonal matrix.
    """

    # Argument is a list
    if(type(arg) is list):
        arg = hstack(arg)

    # Argument is a matrix or object array
    elif(type(arg) is cvxpy_matrix or
         type(arg).__name__ in ARRAY_OBJS):
        (m,n) = arg.shape
        if(m!=1 and n!=1):
            raise ValueError('Argument must be one dimensional')
        elif(n == 1):
            arg = arg.T
    
    # Invalid argument
    else:
        raise ValueError('Invalid argument')

    # Argument is numeric
    numeric = True
    for i in range(0,arg.shape[1],1):
        if(not np.isscalar(arg[0,i])):
            numeric = False
    if(numeric):
        return matrix(np.diagflat(arg))
    
    # Not numeric
    (m,n) = arg.shape
    new_exp = cvxpy_expression(n,n)
    for i in range(0,n,1):
        new_exp[i,i] = arg[0,i]
    return new_exp
Example #10
0
def diag(arg):
    """
    Extract the diagonal from square array-like object.
    """

    # Check size
    (m,n) = arg.shape
    if(m!=n):
        raise ValueError('Invalid dimensions')

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

    # Object array
    elif(type(arg).__name__ in ARRAY_OBJS):
        new_exp = cvxpy_expression(m,1)
        for i in range(0,m,1):
            new_exp[i,0] = arg[i,i]
        return new_exp

    # Error
    else:
        raise ValueError('Invalid argument type')    
Example #11
0
def expand(arg):
    
    # Constant
    if(type(arg) is cvxpy_obj):
        return arg,cvxpy_list([])
    
    # Scalar variable
    elif(type(arg) is cvxpy_scalar_var):
        return arg,cvxpy_list([])

    # Summation
    elif(type(arg) is cvxpy_tree and arg.item.name == '+'):

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

        # New var
        v = var()            
            
        # Expand children
        new_children = []
        new_constr = cvxpy_list([])
        for child in children:
            
            # Multiplication
            if(child.type == TREE and
               child.item.name == '*'):
                child_var,child_constr = expand(child.children[1])
                new_children += [child.children[0].data*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,cvxpy_list([equal(new_tree,v)])+new_constr
        
    # Multiplication
    elif(type(arg) is cvxpy_tree and arg.item.name == '*'):

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

        # New var
        v = var()

        # 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 = cvxpy_list([equal(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 var 
        v = var()

        # Analyze children
        new_children = []
        new_constr = cvxpy_list([])
        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)
        new_constr += item._range_constr(v)
        new_constr += item._dom_constr(new_children)
        return v,cvxpy_list([equal(new_tree,v)])+new_constr
    
    # Constraint
    elif(type(arg) is cvxpy_constr):
        
        # Not set membership
        if(arg.op != 'in'):

            # 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.op,obj2)
            new_list = cvxpy_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.op,arg.right)
            return cvxpy_list([new_constr])+constr_list

    # Array
    elif(type(arg) is cvxpy_expression or
         type(arg) is cvxpy_var):
        (m,n) = arg.shape
        new_list = cvxpy_list([])
        new_exp = cvxpy_expression(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_exp[i,j] = cvxpy_obj(CONSTANT,arg[i,j],str(arg[i,j]))
                    
                # Not a number
                else:
                    obj,constr_list = expand(arg[i,j])
                    new_exp[i,j] = obj
                    new_list += constr_list
        return new_exp,new_list
    
    # List of constraints
    elif(type(arg) is cvxpy_list):

        # Empty list
        if(len(arg) == 0):
            return cvxpy_list([])
        else:
            new_list = map(expand,arg)
            return reduce(lambda x,y:x+y,new_list)

    # Invalid
    else:
        raise ValueError('Invalid argument')
Example #12
0
    def __addsub__(self,other,op):
        """
        Description
        -----------
        Handles left add or left subtract.
        
        Arguments
        ---------
        other: right hand object.
        op: Character (+ or -)
        """

        # Create operator (I should create another class for this)
        operator = cvxpy_obj(OPERATOR,None,'+')

        # Create args to combine
        if(type(self) is cvxpy_tree and
           self.item.name == '+'):
            args = self.children
        else:
            args = [self]

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

        # Scalar variable or scalar param
        elif(type(other) is cvxpy_scalar_var or
             type(other) is cvxpy_scalar_param):
            if(op == '+'):
                return cvxpy_tree(operator,args+[other])
            else:
                return cvxpy_tree(operator,args+[-other])
        
        # Tree
        elif(type(other) is cvxpy_tree):
            if(other.item.name == '+'):
                if(op == '+'):
                    return cvxpy_tree(operator,
                                      args+other.children)
                else:
                    return cvxpy_tree(operator,
                                      args+[-x for x in other.children])
            else:
                if(op == '+'):
                    return cvxpy_tree(operator,args+[other])
                else:
                    return cvxpy_tree(operator,args+[-other])

        # Matrix
        elif(type(other) is cvxpy_matrix):
            m = other.shape[0]
            n = other.shape[1]
            new_exp = cvxpy_expression(m,n)
            for i in range(0,m,1):
                for j in range(0,n,1):
                    if(op == '+'):
                        new_exp[i,j] = self+other[i,j]
                    else:
                        new_exp[i,j] = self-other[i,j]
            return new_exp

        # Not implemented
        else:
            return NotImplemented
Example #13
0
    def __mulhandle__(self,other):
        """
        Description
        -----------
        Handles multiply.
        Note: If other is numeric, the multiplication
        tree formed has the constant object as first child.

        Argument
        --------
        other: Other object.
        """

        # Create operator
        operator = cvxpy_obj(OPERATOR,None,'*')

        # 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 == '+'):
                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 == '*' and
                 self.children[0].type == CONSTANT):
                new_object = other*self.children[0]
                if(new_object.data == 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.data*other,
                                      str(self.data*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 = other.shape[0]
            n = other.shape[1]
            new_exp = cvxpy_expression(m,n)
            for i in range(0,m,1):
                for j in range(0,n,1):
                    new_exp[i,j] = other[i,j]*self
            return new_exp

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

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

        # Not implemented
        else:
            return NotImplemented
Example #14
0
    def __raddsub__(self,other,op):
        """
        Description
        -----------
        Handles right add or right subtract.
        
        Arguments
        ---------
        other: left hand object.
        op: Character (+ or -)
        """

        # Create operator
        operator = cvxpy_obj(OPERATOR,None,'+')

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

        # Number
        if(np.isscalar(other)):
            if(other == 0.0):
                if(op == '+'):
                    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 == '+'):
                return cvxpy_tree(operator,other.children+args)
            else:
                return cvxpy_tree(operator,[other]+args)
                
        # Matrix
        elif(type(other) is cvxpy_matrix):
            m = other.shape[0]
            n = other.shape[1]
            new_exp = cvxpy_expression(m,n)
            for i in range(0,m,1):
                for j in range(0,n,1):
                    if(op == '+'):
                        new_exp[i,j] = other[i,j]+self
                    else:
                        new_exp[i,j] = other[i,j]-self
            return new_exp

        # Not implemented
        else:
            return NotImplemented
Example #15
0
def expand(arg):

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

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

    # Summation
    elif (type(arg) is cvxpy_tree and arg.item.name == '+'):

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

        # New var
        v = var()

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

            # Multiplication
            if (child.type == TREE and child.item.name == '*'):
                child_var, child_constr = expand(child.children[1])
                new_children += [child.children[0].data * 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, cvxpy_list([equal(new_tree, v)]) + new_constr

    # Multiplication
    elif (type(arg) is cvxpy_tree and arg.item.name == '*'):

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

        # New var
        v = var()

        # 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 = cvxpy_list([equal(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 var
        v = var()

        # Analyze children
        new_children = []
        new_constr = cvxpy_list([])
        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)
        new_constr += item._range_constr(v)
        new_constr += item._dom_constr(new_children)
        return v, cvxpy_list([equal(new_tree, v)]) + new_constr

    # Constraint
    elif (type(arg) is cvxpy_constr):

        # Not set membership
        if (arg.op != 'in'):

            # 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.op, obj2)
            new_list = cvxpy_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.op, arg.right)
            return cvxpy_list([new_constr]) + constr_list

    # Array
    elif (type(arg) is cvxpy_expression or type(arg) is cvxpy_var):
        (m, n) = arg.shape
        new_list = cvxpy_list([])
        new_exp = cvxpy_expression(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_exp[i, j] = cvxpy_obj(CONSTANT, arg[i, j],
                                              str(arg[i, j]))

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

    # List of constraints
    elif (type(arg) is cvxpy_list):

        # Empty list
        if (len(arg) == 0):
            return cvxpy_list([])
        else:
            new_list = map(expand, arg)
            return reduce(lambda x, y: x + y, new_list)

    # Invalid
    else:
        raise ValueError('Invalid argument')
Example #16
0
def re_eval(arg,param_map):
    """
    Description
    -----------
    Replaces parameters found in arg using the param_map
    and re-evaluates the resulting object.
    
    Arguments
    ---------
    arg: Argument to be re-evaluated.
    param_map: Dictionery that maps the parameters 
    to objects.
    """

    # Number
    if(np.isscalar(arg)):
        return arg
    
    # Constant object
    elif(type(arg) is cvxpy_obj):
        return arg.get_value()
    
    # Scalar variable
    elif(type(arg) is cvxpy_scalar_var):
        return arg
    
    # Scalar param
    elif(type(arg) is cvxpy_scalar_param):
        return re_eval(param_map[arg],param_map)

    # Summation
    elif(type(arg) is cvxpy_tree and arg.item.name == '+'):
        new_children = map(lambda x:re_eval(x,param_map),arg.children)
        return sum(new_children)

    # Multiplication
    elif(type(arg) is cvxpy_tree and arg.item.name == '*'):
        child1 = re_eval(arg.children[0],param_map)
        child2 = re_eval(arg.children[1],param_map)
        return child1*child2

    # Function
    elif(type(arg) is cvxpy_tree and arg.item.type == FUNCTION):
        new_children = map(lambda x:re_eval(x,param_map),arg.children)
        return arg.item(new_children)

    # Constraint
    elif(type(arg) is cvxpy_constr):
        
        # Not set membership
        if(arg.op != 'in'):
            left = re_eval(arg.left ,param_map)
            right= re_eval(arg.right,param_map)
            if(arg.op == '=='):
                return equal(left,right)
            elif(arg.op == '<='):
                return less(left,right)
            else:
                return greater(left,right)

        # Set membership
        else:
            left = re_eval(arg.left,param_map)
            return belongs(left,arg.right)

    # Array
    elif(type(arg) is cvxpy_expression or
         type(arg) is cvxpy_var or
         type(arg) is cvxpy_param):
        (m,n) = arg.shape
        new_exp = cvxpy_expression(m,n)
        for i in range(0,m,1):
            for j in range(0,n,1):
                new_exp[i,j] = re_eval(arg[i,j],param_map)
        return new_exp

    # List
    elif(type(arg) is cvxpy_list):
        new_list = cvxpy_list([])
        for c in arg:
            new_list += cvxpy_list([re_eval(c,param_map)])
        return new_list

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