Пример #1
0
    def _construct_chain(self, solver=None, gp=False, enforce_dpp=False):
        """
        Construct the chains required to reformulate and solve the problem.

        In particular, this function

        # finds the candidate solvers
        # constructs the solving chain that performs the
           numeric reductions and solves the problem.

        Arguments
        ---------
        solver : str, optional
            The solver to use. Defaults to ECOS.
        gp : bool, optional
            If True, the problem is parsed as a Disciplined Geometric Program
            instead of as a Disciplined Convex Program.
        enforce_dpp : bool, optional
            Whether to error on DPP violations.

        Returns
        -------
        A solving chain
        """
        candidate_solvers = self._find_candidate_solvers(solver=solver, gp=gp)
        return construct_solving_chain(self,
                                       candidate_solvers,
                                       gp=gp,
                                       enforce_dpp=enforce_dpp)
Пример #2
0
def check_solver(prob, solver_name):
    """Can the solver solve the problem?
    """
    try:
        if solver_name == ROBUST_CVXOPT:
            solver_name = CVXOPT
        chain = construct_solving_chain(prob, solver=solver_name)
        return True
    except SolverError:
        return False
    except:
        raise
Пример #3
0
def cvxpy_solve(cvxpy_problem, iters=2, lsqr_iters=30,
                presolve=False, scs_opts={},
                verbose=True, warm_start=True):
    from cvxpy.reductions.solvers.solving_chain import construct_solving_chain

    solving_chain = construct_solving_chain(cvxpy_problem, solver='SCS')
    data, inverse_data = solving_chain.apply(cvxpy_problem)

    start = time.time()
    if presolve:
        scs_solution = solving_chain.solve_via_data(cvxpy_problem,
                                                    data=data,
                                                    warm_start=warm_start,
                                                    verbose=verbose,
                                                    solver_opts=scs_opts)

        A, b, c, z, dims = cvxpy_scs_to_cpr(data, scs_solution)
    else:
        A, b, c, z, dims = cvxpy_scs_to_cpr(data)
        scs_solution = {}
        if warm_start and 'CPR' in cvxpy_problem._solver_cache:
            z = cvxpy_problem._solver_cache['CPR']['z']
    prepare_time = time.time() - start

    # TODO change this

    start = time.time()
    refined_z = refine(A, b, c, dims, z, iters=iters,
                       lsqr_iters=lsqr_iters, verbose=verbose)
    cvxpy_problem._solver_cache['CPR'] = {'z': refined_z}
    refine_time = time.time() - start

    new_residual, u, v = residual_and_uv(
        refined_z, (A.indptr, A.indices, A.data), b, c, make_prod_cone_cache(dims))

    scs_solution['x'], scs_solution['s'], scs_solution[
        'y'], tau, kappa = uv2xsytaukappa(u, v, A.shape[1])

    scs_solution["info"] = {'status': 'Solved', 'solveTime': refine_time,
                            'setupTime': prepare_time, 'iter': iters, 'pobj': scs_solution['x'] @ c if tau > 0 else np.nan}

    cvxpy_problem.unpack_results(scs_solution, solving_chain, inverse_data)

    return cvxpy_problem.value
Пример #4
0
    def get_problem_data(self, solver):
        """Returns the problem data used in the call to the solver.

        When a problem is solved, a chain of reductions, called a
        :class:`~cvxpy.reductions.solvers.solving_chain.SolvingChain`,
        compiles it to some low-level representation that is compatible with
        the targeted solver. This method returns that low-level representation.

        For some solving chains, this low-level representation is a dictionary
        that contains exactly those arguments that were supplied to the solver;
        however, for other solving chains, the data is an intermediate
        representation that is compiled even further by libraries other than
        CVXPY.

        A solution to the equivalent low-level problem can be obtained via the
        data by invoking the solve_via_data method of the returned solving
        chain, a thin wrapper around the code external to CVXPY that further
        processes and solves the problem. Invoke the unpack_results method
        to recover a solution to the original problem.

        Parameters
        ----------
        solver : str
            The solver the problem data is for.

        Returns
        -------
        dict or object
            lowest level representation of problem
        SolvingChain
            The solving chain that created the data.
        list
            The inverse data generated by the chain.
        """
        try:
            solving_chain = construct_solving_chain(self, solver)
        except Exception as e:
            raise e
        data, inv_data = solving_chain.apply(self)
        return data, solving_chain, inv_data
Пример #5
0
    def _construct_chains(self, solver=None, gp=False):
        """
        Construct the chains required to reformulate and solve the problem.

        In particular, this function

        #. finds the candidate solvers
        #. constructs the intermediate chain suitable for numeric reductions.
        #. constructs the solving chain that performs the
           numeric reductions and solves the problem.

        Parameters
        ----------
        solver : str, optional
            The solver to use. Defaults to ECOS.
        gp : bool, optional
            If True, the problem is parsed as a Disciplined Geometric Program
            instead of as a Disciplined Convex Program.
        """

        chain_key = (solver, gp)

        if chain_key != self._cached_chain_key:
            try:
                candidate_solvers = self._find_candidate_solvers(solver=solver,
                                                                 gp=gp)

                self._intermediate_chain = \
                    construct_intermediate_chain(self, candidate_solvers, gp=gp)
                self._intermediate_problem, self._intermediate_inverse_data = \
                    self._intermediate_chain.apply(self)

                self._solving_chain = \
                    construct_solving_chain(self._intermediate_problem,
                                            candidate_solvers)

                self._cached_chain_key = chain_key

            except Exception as e:
                raise e
Пример #6
0
    def _solve(self,
               solver=None,
               ignore_dcp=False,
               warm_start=True,
               verbose=False,
               parallel=False,
               gp=False,
               **kwargs):
        """Solves a DCP compliant optimization problem.

        Saves the values of primal and dual variables in the variable
        and constraint objects, respectively.

        Parameters
        ----------
        solver : str, optional
            The solver to use. Defaults to ECOS.
        ignore_dcp : bool, optional
            TODO(akshayka): This option will probably be eliminated.
            Overrides the default of raising an exception if the problem is not
            DCP.
        warm_start : bool, optional
            Should the previous solver result be used to warm start?
        verbose : bool, optional
            Overrides the default of hiding solver output.
        parallel : bool, optional
            If problem is separable, solve in parallel.
        gp : bool, optional
            If True, then parses the problem as a disciplined geometric program
            instead of a disciplined convex program.
        kwargs : dict, optional
            A dict of options that will be passed to the specific solver.
            In general, these options will override any default settings
            imposed by cvxpy.

        Returns
        -------
        float
            The optimal value for the problem, or a string indicating
            why the problem could not be solved.
        """
        if parallel:
            from cvxpy.transforms.separable_problems import get_separable_problems
            self._separable_problems = (get_separable_problems(self))
            if len(self._separable_problems) > 1:
                return self._parallel_solve(solver, ignore_dcp, warm_start,
                                            verbose, **kwargs)

        chain_key = (solver, gp)
        if chain_key != self._cached_chain_key:
            try:
                self._solving_chain = construct_solving_chain(self,
                                                              solver=solver,
                                                              gp=gp)
            except Exception as e:
                raise e
        self._cached_chain_key = chain_key

        data, inverse_data = self._solving_chain.apply(self)
        solver_output = self._solving_chain.solve_via_data(
            self, data, warm_start, verbose, kwargs)
        self.unpack_results(solver_output, self._solving_chain, inverse_data)
        return self.value
Пример #7
0
    def _solve(self,
               solver=None,
               ignore_dcp=False,
               warm_start=True,
               verbose=False,
               parallel=False,
               **kwargs):
        """Solves a DCP compliant optimization problem.

        Saves the values of primal and dual variables in the variable
        and constraint objects, respectively.

        Parameters
        ----------
        solver : str, optional
            The solver to use. Defaults to ECOS.
        ignore_dcp : bool, optional
            TODO(akshayka): This option will probably be eliminated.
            Overrides the default of raising an exception if the problem is not
            DCP.
        warm_start : bool, optional
            Should the previous solver result be used to warm start?
        verbose : bool, optional
            Overrides the default of hiding solver output.
        parallel : bool, optional
            If problem is separable, solve in parallel.
        kwargs : dict, optional
            A dict of options that will be passed to the specific solver.
            In general, these options will override any default settings
            imposed by cvxpy.

        Returns
        -------
        float
            The optimal value for the problem, or a string indicating
            why the problem could not be solved.
        """
        if parallel:
            from cvxpy.transforms.separable_problems import get_separable_problems
            self._separable_problems = (get_separable_problems(self))
            if len(self._separable_problems) > 1:
                return self._parallel_solve(solver, ignore_dcp, warm_start,
                                            verbose, **kwargs)

        # If a previous chain does not exist, or if the solver is
        # specified and it does not match the solver used for the previous
        # solve, then construct a new solving chain.
        if (self._solving_chain is None
                or (solver is not None
                    and self._solving_chain.solver.name != solver)):
            try:
                self._solving_chain = construct_solving_chain(self,
                                                              solver=solver)
            except Exception as e:
                raise e

        data, inverse_data = self._solving_chain.apply(self)
        solution = self._solving_chain.solve_via_data(self, data, warm_start,
                                                      verbose, kwargs)
        self.unpack_results(solution, self._solving_chain, inverse_data)
        return self.value
Пример #8
0
def cvxpy_differentiate(cvxpy_problem, parameters, output_expression,
                        iters=2, lsqr_iters=30, derive_lsqr_iters=100,
                        presolve=False, scs_opts={},
                        verbose=True, warm_start=True):
    """Compute the derivative matrix of the solution map of
    a CVXPY problem, whose input is a list of CVXPY parameters,
    and output is a CVXPY one-dimensional expression of the solution,
    the constraint violations, or the dual parameters.

    Only affine CVXPY transformations are allowed.
    """

    solving_chain = construct_solving_chain(cvxpy_problem, solver='SCS')
    data, inverse_data = solving_chain.apply(cvxpy_problem)
    A, b, c, _, _ = cvxpy_scs_to_cpr(data)

    # A is a sparse matrix, so below we compute
    # sparse matrix differences.

    input_mappings = []

    # make mapping from input parameters to data
    for parameter in parameters:
        if verbose:
            print('compiling parameter', parameter.name())
        old_par_val = parameter.value
        parameter.value += 1.
        newdata, _ = solving_chain.apply(cvxpy_problem)
        new_A, new_b, new_c, _, _ = cvxpy_scs_to_cpr(newdata)
        dA = new_A - A
        db = new_b - b
        dc = new_c - c
        parameter.value -= 2.
        newdata, _ = solving_chain.apply(cvxpy_problem)
        new_A, new_b, new_c, _, _ = cvxpy_scs_to_cpr(newdata)
        if not (np.allclose(A - new_A, dA)) \
                and (np.allclose(b - new_b, db))\
                and (np.allclose(c - new_c, dc)):
            raise NotAffine('on parameter %s' % parameter.name())
        parameter.value = old_par_val
        input_mappings.append((dA, db, dc))

    _ = cvxpy_solve(cvxpy_problem, iters=iters, lsqr_iters=lsqr_iters,
                    presolve=presolve, scs_opts=scs_opts,
                    verbose=verbose, warm_start=warm_start)

    # used by cvxpy to transform back
    scs_solution = {}
    scs_solution["info"] = {'status': 'Solved', 'solveTime': 0.,
                            'setupTime': 0., 'iter': 0, 'pobj': np.nan}

    z = cvxpy_problem._solver_cache['CPR']['z']

    if not (len(output_expression.shape) == 1):
        raise ValueError('Only one-dimensional outputs')
    output_matrix = np.empty((len(z), output_expression.size))
    base = output_expression.value

    # make mapping from z to output
    for i in range(len(z)):
        # perturb z
        old_val = z[i]
        z[i] += old_val * 1e-8
        _, new_u, new_v = residual_and_uv(
            z, (A.indptr, A.indices, A.data), b, c,
            make_prod_cone_cache(dims))
        scs_solution['x'], scs_solution['s'], scs_solution[
            'y'], tau, kappa = uv2xsytaukappa(new_u, new_v, A.shape[1])
        cvxpy_problem.unpack_results(scs_solution, solving_chain,
                                     inverse_data)

        output_matrix[i, :] = output_expression.value - base

        z[i] -= old_val * 2e-8
        _, new_u, new_v = residual_and_uv(
            z, (A.indptr, A.indices, A.data), b, c,
            make_prod_cone_cache(dims))
        scs_solution['x'], scs_solution['s'], scs_solution[
            'y'], tau, kappa = uv2xsytaukappa(new_u, new_v, A.shape[1])
        cvxpy_problem.unpack_results(scs_solution, solving_chain,
                                     inverse_data)

        if not np.allclose(output_matrix[i, :],
                           base - output_expression.value):
            raise NotAffine('on solution variable z[%d]' % i)

        z[i] = old_val

    def matvec(d_parameters):
        assert len(d_parameters) == len(parameters)
        total_dA = sp.csc_matrix()
        total_db = np.zeros(len(b))
        total_dc = np.zeros(len(c))

        for i in len(d_parameters):
            total_dA += input_mappings[i][0] * d_parameters[i]
            total_db += input_mappings[i][1] * d_parameters[i]
            total_dc += input_mappings[i][2] * d_parameters[i]

        refined_z = refine(A + total_dA, b + total_db,
                           c + total_dc, dims, z, iters=1,
                           lsqr_iters=derive_lsqr_iters, verbose=verbose)
        dz = refined_z - z
        return dz @ output_matrix

    def rmatvec(d_output):
        dz = output_matrix @ d_output

    result = LinearOperator((len(parameters), output_expression.size),
                            matvec=matvec,
                            rmatvec=rmatvec,
                            dtype=np.float)