Exemplo n.º 1
0
    def solve(self, quiet=False, return_status=False):
        """
        Solves optimization program using current
        parameter values.
        """

        # Check DCP
        if not self.is_dcp():
            raise ValueError('Program is not DCP')

        # Create param-value map
        replace_map = {}
        for param in self.parameters:
            if np.isnan(param.value):
                raise ValueError('Invalid parameter value: NaN')
            else:
                replace_map[param] = param.value

        # Create new program
        new_p = cvxpy_program(self.action, re_eval(self.objective,
                                                   replace_map),
                              re_eval(self.constraints, replace_map), [],
                              self.options, '')

        # Solve new program
        obj, valid = solve_prog(new_p, quiet)
        if return_status:
            return obj, valid
        else:
            return obj
Exemplo n.º 2
0
    def solve(self,quiet=False,return_status=False):
        """
        Solves optimization program using current
        parameter values.
        """

        # Check DCP
        if not self.is_dcp():
            raise ValueError('Program is not DCP')

        # Create param-value map
        replace_map = {}
        for param in self.parameters:
            if np.isnan(param.value):
                raise ValueError('Invalid parameter value: NaN')
            else:
                replace_map[param] = param.value
        
        # Create new program
        new_p = cvxpy_program(self.action,
                              re_eval(self.objective,replace_map),
                              re_eval(self.constraints,replace_map),
                              [],self.options,'')

        # Solve new program
        obj,valid = solve_prog(new_p,quiet)
        if return_status:
            return obj,valid
        else:
            return obj
Exemplo n.º 3
0
    def _solve_isolating(self, *args):
        """
        Description
        -----------
        Isolate parameters and then solve program.
        Used by linearize method to obtain subgradient.
        Arguments must be numbers. A very important 
        point is that solve_isolating introduces
        equality constraints and places them at the
        beginning of the constraint list. This is 
        later used to construct the subgradient.
        """

        # Process input
        if (len(args) != 0 and type(args[0]) is list):
            args = args[0]

        # Create argument list
        arg_list = []
        for arg in args:
            if (np.isscalar(arg)):
                arg_list += [arg]
            elif (type(arg) is cvxpy_matrix):
                (m, n) = arg.shape
                for i in range(0, m, 1):
                    for j in range(0, n, 1):
                        arg_list += [arg[i, j]]
            else:
                raise ValueError('Arguments must be numeric')

        # Check number of arguments
        if (len(arg_list) != len(self.params)):
            raise ValueError('Invalid number of arguments')

        # Isolate parameters
        p1_map = {}
        new_constr = cvxpy_list([])
        for p in self.params:
            v = var('v_' + p.name)
            p1_map[p] = v
            new_constr += cvxpy_list([equal(v, p)])
        new_p1 = prog((self.action, re_eval(self.obj, p1_map)),
                      new_constr + re_eval(self.constr, p1_map), self.params,
                      self.options, self.name)

        # Substitute parameters with arguments
        p2_map = {}
        for k in range(0, len(arg_list), 1):
            p2_map[new_p1.params[k]] = arg_list[k]
        new_p2 = prog((new_p1.action, re_eval(new_p1.obj, p2_map)),
                      re_eval(new_p1.constr, p2_map), [], new_p1.options,
                      new_p1.name)

        # Solve program
        obj, lagrange_mul_eq = solve_prog(new_p2)
        self.lagrange_mul_eq = lagrange_mul_eq
        return obj
Exemplo n.º 4
0
    def _solve_isolating(self,*args):
        """
        Description
        -----------
        Isolate parameters and then solve program.
        Used by linearize method to obtain subgradient.
        Arguments must be numbers. A very important 
        point is that solve_isolating introduces
        equality constraints and places them at the
        beginning of the constraint list. This is 
        later used to construct the subgradient.
        """

        # Process input
        if(len(args) != 0 and type(args[0]) is list):
            args = args[0]
        
        # Create argument list
        arg_list = []
        for arg in args:
            if(np.isscalar(arg)):
                arg_list += [arg]
            elif(type(arg) is cvxpy_matrix):
                (m,n) = arg.shape
                for i in range(0,m,1):
                    for j in range(0,n,1):
                        arg_list += [arg[i,j]]
            else:
                raise ValueError('Arguments must be numeric')

        # Check number of arguments
        if(len(arg_list) != len(self.params)):
            raise ValueError('Invalid number of arguments')

        # Isolate parameters
        p1_map = {}
        new_constr = cvxpy_list([])
        for p in self.params:
            v = var('v_'+p.name)
            p1_map[p] = v
            new_constr += cvxpy_list([equal(v,p)])
        new_p1 = prog((self.action,re_eval(self.obj,p1_map)),
                      new_constr+re_eval(self.constr,p1_map),
                      self.params, self.options,self.name)

        # Substitute parameters with arguments
        p2_map = {}
        for k in range(0,len(arg_list),1):
            p2_map[new_p1.params[k]] = arg_list[k]
        new_p2 = prog((new_p1.action,re_eval(new_p1.obj,p2_map)),
                      re_eval(new_p1.constr,p2_map),
                      [],new_p1.options,new_p1.name)

        # Solve program
        obj,lagrange_mul_eq = solve_prog(new_p2)
        self.lagrange_mul_eq = lagrange_mul_eq
        return obj
Exemplo n.º 5
0
    def is_dcp(self,args=None):
        """
        Description
        -----------
        Checks if the program follows DCP rules.
        If args is None, the check is done on the
        body of the program. If args is a list of
        arguments, the parameters are replaced
        with the arguments and the check is done
        on the resulting program. This function
        is called with a list of arguments when 
        cvxpy_tree.is_dcp is executed.
        
        Arguments
        ---------
        args: List of arguments
        """

        # No arguments: Check body of program
        if(args == None):
            if(self.action == MINIMIZE and
               not self.obj.is_convex()):
                return False
            elif(self.action == MAXIMIZE and
                 not self.obj.is_concave()):
                return False
            else:
                return self.constr.is_dcp()

        # Arguments given: Replace parameters and then check
        else:

            # Check if some argument has parameters
            if(len(cvxpy_list(args).get_params()) != 0):
                return False

            # Create a param-arg map
            p_map = {}
            for k in range(0,len(args),1):
                p_map[self.params[k]] = args[k]

            # Re-evaluate
            new_p = prog((self.action,re_eval(self.obj,p_map)),
                         re_eval(self.constr,p_map))

            # Check dcp on resulting program
            return new_p.is_dcp()
Exemplo n.º 6
0
    def is_dcp(self, args=None):
        """
        Description
        -----------
        Checks if the program follows DCP rules.
        If args is None, the check is done on the
        body of the program. If args is a list of
        arguments, the parameters are replaced
        with the arguments and the check is done
        on the resulting program. This function
        is called with a list of arguments when 
        cvxpy_tree.is_dcp is executed.
        
        Arguments
        ---------
        args: List of arguments
        """

        # No arguments: Check body of program
        if (args == None):
            if (self.action == MINIMIZE and not self.obj.is_convex()):
                return False
            elif (self.action == MAXIMIZE and not self.obj.is_concave()):
                return False
            else:
                return self.constr.is_dcp()

        # Arguments given: Replace parameters and then check
        else:

            # Check if some argument has parameters
            if (len(cvxpy_list(args).get_params()) != 0):
                return False

            # Create a param-arg map
            p_map = {}
            for k in range(0, len(args), 1):
                p_map[self.params[k]] = args[k]

            # Re-evaluate
            new_p = prog((self.action, re_eval(self.obj, p_map)),
                         re_eval(self.constr, p_map))

            # Check dcp on resulting program
            return new_p.is_dcp()
Exemplo n.º 7
0
    def _pm_expand(self,constr):
        """
        Description
        -----------
        Given the constraint, which must be in the form
        self(args) operator variable, the parameters
        are replaced with arguments and then the 
        partial minimization description of the program
        is merged with the constraint.

        Argument
        --------
        constr: cvxpy_constr of the form self(args) 
        operator variable.
        """

        # Get arguments
        args = constr.left.children

        # Create arg-param map by position
        p_map = {}
        for k in range(0,len(args),1):
            p_map[self.params[k]] = args[k]

        # Create new program
        new_p = prog((self.action,re_eval(self.obj,p_map)),
                     re_eval(self.constr,p_map),[],
                     self.options,self.name)

        # Expand partial minimization
        right = constr.right
        new_constr = []
        if(self.curvature == CONVEX):
            new_constr += [less(new_p.obj,right)]
        else:
            new_constr += [greater(new_p.obj,right)]
        new_constr += new_p.constr
        
        # Return constraints
        return cvxpy_list(new_constr)
Exemplo n.º 8
0
    def _pm_expand(self, constr):
        """
        Description
        -----------
        Given the constraint, which must be in the form
        self(args) operator variable, the parameters
        are replaced with arguments and then the 
        partial minimization description of the program
        is merged with the constraint.

        Argument
        --------
        constr: cvxpy_constr of the form self(args) 
        operator variable.
        """

        # Get arguments
        args = constr.left.children

        # Create arg-param map by position
        p_map = {}
        for k in range(0, len(args), 1):
            p_map[self.params[k]] = args[k]

        # Create new program
        new_p = prog((self.action, re_eval(self.obj, p_map)),
                     re_eval(self.constr, p_map), [], self.options, self.name)

        # Expand partial minimization
        right = constr.right
        new_constr = []
        if (self.curvature == CONVEX):
            new_constr += [less(new_p.obj, right)]
        else:
            new_constr += [greater(new_p.obj, right)]
        new_constr += new_p.constr

        # Return constraints
        return cvxpy_list(new_constr)
Exemplo n.º 9
0
    def _pm_expand(self,constr):
        """
        Returns constraints that embed the program into
        the parent program.

        :param constr: cvxpy_constr of the form 
                       self(args), comparison-type, variable.
        """

        # Get arguments
        args = constr.left.children

        # Create argument reference list
        args_ref = self._get_expanded_objects(self.formals)
        
        # Check number of arguments
        if len(args) != len(args_ref):
            raise TypeError("Invalid number of arguments")

        # Create map and new program
        replace_map = {}
        for k in range(0,len(args),1):
            replace_map[args_ref[k]] = args[k]
        new_p = cvxpy_program(self.action,
                              re_eval(self.objective,replace_map),
                              re_eval(self.constraints,replace_map),
                              [],self.options,'')

        # Embed
        right = constr.right
        new_constr = []
        if self.action == MINIMIZE:
            new_constr += [compare(new_p.objective,LESS_EQUALS,right)]
        else:
            new_constr += [compare(new_p.objective,GREATER_EQUALS,right)]
        new_constr += new_p.constraints
        
        # Return constraints
        return new_constr
Exemplo n.º 10
0
    def is_dcp(self,args=None):
        """
        Determines if program is DCP-compliant.

        :param args: List of scalar arguments.
        """

        # No arguments: Check body of program
        if args == None:
            if (self.action == MINIMIZE and
                not self.objective.is_convex()):
                return False
            elif (self.action == MAXIMIZE and
                  not self.objective.is_concave()):
                return False
            else:
                return self.constraints.is_dcp()

        # Arguments given: Replace arguments and then check
        else:

            # Create reference list of arguments
            args_ref = self._get_expanded_objects(self.formals)

            # Check number of arguments
            if len(args) != len(args_ref):
                raise TypeError('Invalid number of arguments')

            # Create map and new program
            replace_map = {}
            for k in range(0,len(args),1):
                replace_map[args_ref[k]] = args[k]
            new_p = cvxpy_program(self.action,
                                  re_eval(self.objective,replace_map),
                                  re_eval(self.constraints,replace_map),
                                  [],self.options,'')

            # Check dcp on resulting program
            return new_p.is_dcp()
Exemplo n.º 11
0
    def _pm_expand(self, constr):
        """
        Returns constraints that embed the program into
        the parent program.

        :param constr: cvxpy_constr of the form 
                       self(args), comparison-type, variable.
        """

        # Get arguments
        args = constr.left.children

        # Create argument reference list
        args_ref = self._get_expanded_objects(self.formals)

        # Check number of arguments
        if len(args) != len(args_ref):
            raise TypeError("Invalid number of arguments")

        # Create map and new program
        replace_map = {}
        for k in range(0, len(args), 1):
            replace_map[args_ref[k]] = args[k]
        new_p = cvxpy_program(self.action, re_eval(self.objective,
                                                   replace_map),
                              re_eval(self.constraints, replace_map), [],
                              self.options, '')

        # Embed
        right = constr.right
        new_constr = []
        if self.action == MINIMIZE:
            new_constr += [compare(new_p.objective, LESS_EQUALS, right)]
        else:
            new_constr += [compare(new_p.objective, GREATER_EQUALS, right)]
        new_constr += new_p.constraints

        # Return constraints
        return new_constr
Exemplo n.º 12
0
    def is_dcp(self, args=None):
        """
        Determines if program is DCP-compliant.

        :param args: List of scalar arguments.
        """

        # No arguments: Check body of program
        if args == None:
            if (self.action == MINIMIZE and not self.objective.is_convex()):
                return False
            elif (self.action == MAXIMIZE and not self.objective.is_concave()):
                return False
            else:
                return self.constraints.is_dcp()

        # Arguments given: Replace arguments and then check
        else:

            # Create reference list of arguments
            args_ref = self._get_expanded_objects(self.formals)

            # Check number of arguments
            if len(args) != len(args_ref):
                raise TypeError('Invalid number of arguments')

            # Create map and new program
            replace_map = {}
            for k in range(0, len(args), 1):
                replace_map[args_ref[k]] = args[k]
            new_p = cvxpy_program(self.action,
                                  re_eval(self.objective, replace_map),
                                  re_eval(self.constraints, replace_map), [],
                                  self.options, '')

            # Check dcp on resulting program
            return new_p.is_dcp()
Exemplo n.º 13
0
    def __call__(self, *args):
        """
        Description
        -----------
        Call program with specified arguments.
        Parameters are substituted with arguments.
        If all arguments are numeric, the resulting
        optimization program is solved. If some
        arguments are object, a tree is returned.
        
        Arguments
        ---------
        args: List of arguments.
        (Can be numbers or objects)
        """

        # Process input
        if (len(args) != 0 and type(args[0]) is list):
            args = args[0]

        # Create argument list
        arg_list = []
        for arg in args:
            if (np.isscalar(arg) or type(arg).__name__ in SCALAR_OBJS):
                arg_list += [arg]
            elif (type(arg) is cvxpy_matrix
                  or type(arg).__name__ in ARRAY_OBJS):
                (m, n) = arg.shape
                for i in range(0, m, 1):
                    for j in range(0, n, 1):
                        arg_list += [arg[i, j]]
            else:
                raise ValueError('Invalid argument type')

        # Check number of arguments
        if (len(arg_list) != len(self.params)):
            raise ValueError('Invalid argument syntax')

        # Solve if numeric
        if (len(arg_list) == 0
                or reduce(lambda x, y: x and y,
                          map(lambda x: np.isscalar(x), arg_list))):

            # Substitute parameters with arguments
            p1_map = {}
            for k in range(0, len(arg_list), 1):
                p1_map[self.params[k]] = arg_list[k]
            new_p = prog((self.action, re_eval(self.obj, p1_map)),
                         re_eval(self.constr, p1_map), [], self.options,
                         self.name)

            # Solve program
            obj, lagrange_mul_eq = solve_prog(new_p)
            return obj

        # Upgrade numbers to objects
        for i in range(0, len(arg_list), 1):
            if (np.isscalar(arg_list[i])):
                arg_list[i] = cvxpy_obj(CONSTANT, arg_list[i],
                                        str(arg_list[i]))

        # Return tree
        return cvxpy_tree(self, arg_list)
Exemplo n.º 14
0
    def __call__(self,*args):
        """
        Invokes program.

        :param args: List of arguments.        
        """
        
        # Get arguments reference
        args_ref = self._get_expanded_objects(self.formals)
        
        # Internal call
        if len(args) == 1 and type(args[0]) is list:
            
            # Get list of arguments
            args_list = args[0]

            # Check number of arguments
            if len(args_list) != len(args_ref):
                raise TypeError('Invalid number of arguments')

        # User call
        else:
     
            # Check number of arguments
            if len(args) != len(self.formals):
                raise TypeError('Invalid number of arguments')

            # Check syntax
            for i in range(0,len(args),1):
                if (np.isscalar(args[i]) or 
                    type(args[i]).__name__ in SCALAR_OBJS):
                    if self.formals[i].shape != (1,1):
                        raise ValueError('Invalid argument shape')
                elif (type(args[i]) is cvxpy_matrix or 
                      type(args[i]).__name__ in ARRAY_OBJS):
                    if self.formals[i].shape != args[i].shape:
                        raise ValueError('Invalid argument shape')
                else:
                    raise TypeError('Invalid argument')

            # Expand arguments
            args_list = self._get_expanded_objects(args)

        # Verify values
        for i in range(0,len(args_ref)):
            if np.isscalar(args_list[i]) and np.isnan(args_list[i]):
                raise ValueError('Invalid argument value: NaN')

        # Upgrade scalars to objects
        args_upgraded = self._upgrade_scalars(args_list)

        # Verify replacements
        for i in range(0,len(args_ref)):
            if (len(args_upgraded[i].variables) != 0 and
                type(args_ref[i]) is not cvxpy_scalar_var):
                raise TypeError('Invalid replacement')

        # All numeric
        if all(list(map(lambda x: type(x) is cvxpy_obj,args_upgraded))):

            # Create map and new program
            replace_map = {}
            for i in range(0,len(args_ref),1):
                replace_map[args_ref[i]] = args_upgraded[i]
            new_p = cvxpy_program(self.action,
                                  re_eval(self.objective,replace_map),
                                  re_eval(self.constraints,replace_map),
                                  [],self.options,'')

            # Solve
            obj,valid = new_p.solve(quiet=True,return_status=True)
            if not valid:
                raise ValueError('Unable to compute value')
            else:
                return obj
        
        # Not all numeric
        else:
            
            # Return expression tree
            return cvxpy_tree(self,args_upgraded)
Exemplo n.º 15
0
    def __call__(self,*args):
        """
        Description
        -----------
        Call program with specified arguments.
        Parameters are substituted with arguments.
        If all arguments are numeric, the resulting
        optimization program is solved. If some
        arguments are object, a tree is returned.
        
        Arguments
        ---------
        args: List of arguments.
        (Can be numbers or objects)
        """

        # Process input
        if(len(args) != 0 and type(args[0]) is list):
            args = args[0]
        
        # Create argument list
        arg_list = []
        for arg in args:
            if(np.isscalar(arg) or 
               type(arg).__name__ in SCALAR_OBJS):
                arg_list += [arg]
            elif(type(arg) is cvxpy_matrix or 
                 type(arg).__name__ in ARRAY_OBJS):
                (m,n) = arg.shape
                for i in range(0,m,1):
                    for j in range(0,n,1):
                        arg_list += [arg[i,j]]
            else:
                raise ValueError('Invalid argument type')

        # Check number of arguments
        if(len(arg_list) != len(self.params)):
            raise ValueError('Invalid argument syntax')
    
        # Solve if numeric
        if(len(arg_list) == 0 or
           reduce(lambda x,y: x and y,
                  map(lambda x: np.isscalar(x),arg_list))):

            # Substitute parameters with arguments
            p1_map = {}
            for k in range(0,len(arg_list),1):
                p1_map[self.params[k]] = arg_list[k]
            new_p = prog((self.action,re_eval(self.obj,p1_map)),
                         re_eval(self.constr,p1_map),[],
                         self.options,self.name)
            
            # Solve program
            obj,lagrange_mul_eq = solve_prog(new_p)
            return obj        

        # Upgrade numbers to objects
        for i in range(0,len(arg_list),1):
            if(np.isscalar(arg_list[i])):
                arg_list[i] = cvxpy_obj(CONSTANT,
                                        arg_list[i],
                                        str(arg_list[i]))

        # Return tree
        return cvxpy_tree(self,arg_list)
Exemplo n.º 16
0
    def __call__(self, *args):
        """
        Invokes program.

        :param args: List of arguments.        
        """

        # Get arguments reference
        args_ref = self._get_expanded_objects(self.formals)

        # Internal call
        if len(args) == 1 and type(args[0]) is list:

            # Get list of arguments
            args_list = args[0]

            # Check number of arguments
            if len(args_list) != len(args_ref):
                raise TypeError('Invalid number of arguments')

        # User call
        else:

            # Check number of arguments
            if len(args) != len(self.formals):
                raise TypeError('Invalid number of arguments')

            # Check syntax
            for i in range(0, len(args), 1):
                if (np.isscalar(args[i])
                        or type(args[i]).__name__ in SCALAR_OBJS):
                    if self.formals[i].shape != (1, 1):
                        raise ValueError('Invalid argument shape')
                elif (type(args[i]) is cvxpy_matrix
                      or type(args[i]).__name__ in ARRAY_OBJS):
                    if self.formals[i].shape != args[i].shape:
                        raise ValueError('Invalid argument shape')
                else:
                    raise TypeError('Invalid argument')

            # Expand arguments
            args_list = self._get_expanded_objects(args)

        # Verify values
        for i in range(0, len(args_ref)):
            if np.isscalar(args_list[i]) and np.isnan(args_list[i]):
                raise ValueError('Invalid argument value: NaN')

        # Upgrade scalars to objects
        args_upgraded = self._upgrade_scalars(args_list)

        # Verify replacements
        for i in range(0, len(args_ref)):
            if (len(args_upgraded[i].variables) != 0
                    and type(args_ref[i]) is not cvxpy_scalar_var):
                raise TypeError('Invalid replacement')

        # All numeric
        if all(list(map(lambda x: type(x) is cvxpy_obj, args_upgraded))):

            # Create map and new program
            replace_map = {}
            for i in range(0, len(args_ref), 1):
                replace_map[args_ref[i]] = args_upgraded[i]
            new_p = cvxpy_program(self.action,
                                  re_eval(self.objective, replace_map),
                                  re_eval(self.constraints, replace_map), [],
                                  self.options, '')

            # Solve
            obj, valid = new_p.solve(quiet=True, return_status=True)
            if not valid:
                raise ValueError('Unable to compute value')
            else:
                return obj

        # Not all numeric
        else:

            # Return expression tree
            return cvxpy_tree(self, args_upgraded)