Esempio n. 1
0
    def test_basic_without_interval(self):
        x = cp.Variable()
        expr = cp.ceil(x)

        self.assertTrue(expr.is_dqcp())
        self.assertTrue(expr.is_quasiconvex())
        self.assertTrue(expr.is_quasiconcave())
        self.assertFalse(expr.is_convex())
        self.assertFalse(expr.is_concave())
        self.assertFalse(expr.is_dcp())
        self.assertFalse(expr.is_dgp())

        problem = cp.Problem(cp.Minimize(expr), [x >= 12, x <= 17])
        self.assertTrue(problem.is_dqcp())
        self.assertFalse(problem.is_dcp())
        self.assertFalse(problem.is_dgp())

        red = cp.Dqcp2Dcp(problem)
        reduced = red.reduce()
        self.assertTrue(reduced.is_dcp())
        self.assertEqual(len(reduced.parameters()), 1)
        soln = bisection.bisect(reduced)
        self.assertAlmostEqual(soln.opt_val, 12.0, places=3)

        problem.unpack(soln)
        self.assertEqual(soln.opt_val, problem.value)
        self.assertAlmostEqual(x.value, 12.0, places=3)
Esempio n. 2
0
    def _solve(self,
               solver=None,
               warm_start=True,
               verbose=False,
               gp=False,
               qcp=False,
               requires_grad=False,
               enforce_dpp=False,
               **kwargs):
        """Solves a DCP compliant optimization problem.

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

        Arguments
        ---------
        solver : str, optional
            The solver to use. Defaults to ECOS.
        warm_start : bool, optional
            Should the previous solver result be used to warm start?
        verbose : bool, optional
            Overrides the default of hiding solver output.
        gp : bool, optional
            If True, parses the problem as a disciplined geometric program.
        qcp : bool, optional
            If True, parses the problem as a disciplined quasiconvex program.
        requires_grad : bool, optional
            Makes it possible to compute gradients with respect to
            parameters by calling `backward()` after solving, or to compute
            perturbations to the variables by calling `derivative()`. When
            True, the solver must be SCS, and dqcp must be False.
            A DPPError is thrown when problem is not DPP.
        enforce_dpp : bool, optional
            When True, a DPPError will be thrown when trying to solve a non-DPP
            problem (instead of just a warning). Defaults to False.
        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.
        """
        for parameter in self.parameters():
            if parameter.value is None:
                raise error.ParameterError(
                    "A Parameter (whose name is '%s') does not have a value "
                    "associated with it; all Parameter objects must have "
                    "values before solving a problem." % parameter.name())

        if requires_grad:
            dpp_context = 'dgp' if gp else 'dcp'
            if qcp:
                raise ValueError("Cannot compute gradients of DQCP problems.")
            elif not self.is_dpp(dpp_context):
                raise error.DPPError("Problem is not DPP (when requires_grad "
                                     "is True, problem must be DPP).")
            elif solver is not None and solver not in [s.SCS, s.DIFFCP]:
                raise ValueError("When requires_grad is True, the only "
                                 "supported solver is SCS "
                                 "(received %s)." % solver)
            elif s.DIFFCP not in slv_def.INSTALLED_SOLVERS:
                raise ImportError(
                    "The Python package diffcp must be installed to "
                    "differentiate through problems. Please follow the "
                    "installation instructions at "
                    "https://github.com/cvxgrp/diffcp")
            else:
                solver = s.DIFFCP
        else:
            if gp and qcp:
                raise ValueError("At most one of `gp` and `qcp` can be True.")
            if qcp and not self.is_dcp():
                if not self.is_dqcp():
                    raise error.DQCPError("The problem is not DQCP.")
                reductions = [dqcp2dcp.Dqcp2Dcp()]
                if type(self.objective) == Maximize:
                    reductions = [FlipObjective()] + reductions
                chain = Chain(problem=self, reductions=reductions)
                soln = bisection.bisect(chain.reduce(),
                                        solver=solver,
                                        verbose=verbose,
                                        **kwargs)
                self.unpack(chain.retrieve(soln))
                return self.value

        data, solving_chain, inverse_data = self.get_problem_data(
            solver, gp, enforce_dpp)
        solution = solving_chain.solve_via_data(self, data, warm_start,
                                                verbose, kwargs)
        self.unpack_results(solution, solving_chain, inverse_data)
        return self.value
Esempio n. 3
0
    def _solve(self,
               solver=None,
               warm_start=True,
               verbose=False,
               parallel=False,
               gp=False,
               qcp=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.
        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, parses the problem as a disciplined geometric program.
        qcp : bool, optional
            If True, parses the problem as a disciplined quasiconvex 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 gp and qcp:
            raise ValueError("At most one of `gp` and `qcp` can be True.")
        if qcp and not self.is_dcp():
            if not self.is_dqcp():
                raise error.DQCPError("The problem is not DQCP.")
            reductions = [dqcp2dcp.Dqcp2Dcp()]
            if type(self.objective) == Maximize:
                reductions = [FlipObjective()] + reductions
            chain = Chain(problem=self, reductions=reductions)
            soln = bisection.bisect(chain.reduce(),
                                    solver=solver,
                                    verbose=verbose,
                                    **kwargs)
            self.unpack(chain.retrieve(soln))
            return self.value
        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, warm_start, verbose,
                                            **kwargs)

        self._construct_chains(solver=solver, gp=gp)
        data, solving_inverse_data = self._solving_chain.apply(
            self._intermediate_problem)
        solution = self._solving_chain.solve_via_data(self, data, warm_start,
                                                      verbose, kwargs)
        full_chain = self._solving_chain.prepend(self._intermediate_chain)
        inverse_data = self._intermediate_inverse_data + solving_inverse_data
        self.unpack_results(solution, full_chain, inverse_data)
        return self.value