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
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