예제 #1
0
    def graph_implementation(self, arg_objs, shape, data=None):
        """Multiply the linear expressions.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        shape : tuple
            The shape of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of constraints)
        """
        # Promote shapes for compatibility with CVXCanon
        lhs = arg_objs[0]
        rhs = arg_objs[1]
        if self.args[0].is_constant():
            return (lu.mul_expr(lhs, rhs, shape), [])
        elif self.args[1].is_constant():
            return (lu.rmul_expr(lhs, rhs, shape), [])
        else:
            raise DCPError("Product of two non-constant expressions is not "
                           "DCP.")
예제 #2
0
 def __mul__(self, other):
     """The product of two expressions.
     """
     # Multiplying by a constant on the right is handled differently
     # from multiplying by a constant on the left.
     if self.is_constant():
         # TODO HACK catch c.T*x where c is a NumPy 1D array.
         if self.size[0] == other.size[0] and \
            self.size[1] != self.size[0] and \
            isinstance(self, cvxtypes.constant()) and self.is_1D_array:
             self = self.T
         return cvxtypes.mul_expr()(self, other)
     elif other.is_constant():
         # Having the constant on the left is more efficient.
         if self.is_scalar() or other.is_scalar():
             return cvxtypes.mul_expr()(other, self)
         else:
             return cvxtypes.rmul_expr()(self, other)
     # When both expressions are not constant
     # Allow affine * affine but raise DCPError otherwise
     # Cannot multiply two non-constant expressions.
     elif self.is_affine() and other.is_affine():
         warnings.warn("Forming a nonconvex expression (affine)*(affine).")
         return cvxtypes.affine_prod_expr()(self, other)
     else:
         raise DCPError("Cannot multiply %s and %s." % (self.curvature, other.curvature))
예제 #3
0
    def graph_implementation(self, arg_objs, shape, data=None):
        """Multiply the expressions elementwise.

        Parameters
        ----------
        arg_objs : list
            LinExpr for each argument.
        shape : tuple
            The shape of the resulting expression.
        data :
            Additional data required by the atom.

        Returns
        -------
        tuple
            (LinOp for objective, list of exprraints)
        """
        # promote if necessary.
        lhs = arg_objs[0]
        rhs = arg_objs[1]
        if self.args[0].is_constant():
            return (lu.multiply(lhs, rhs), [])
        elif self.args[1].is_constant():
            return (lu.multiply(rhs, lhs), [])
        else:
            raise DCPError("Product of two non-constant expressions is not "
                           "DCP.")
예제 #4
0
 def __init__(self, objective, constraints=None):
     if constraints is None:
         constraints = []
     # Check that objective is Minimize or Maximize.
     if not isinstance(objective, (Minimize, Maximize)):
         raise DCPError("Problem objective must be Minimize or Maximize.")
     # Constraints and objective are immutable.
     self._objective = objective
     self._constraints = [c for c in constraints]
     # Cache the variables as a list.
     self._vars = self._variables()
     self._value = None
     self._status = None
     self._solution = None
     # The solving chain with which to solve the problem
     self._solving_chain = None
     self._cached_chain_key = None
     # List of separable (sub)problems
     self._separable_problems = None
     # Information about the shape of the problem and its constituent parts
     self._size_metrics = SizeMetrics(self)
     # Benchmarks reported by the solver:
     self._solver_stats = None
     self.args = [self._objective, self._constraints]
     # Cache for warm start.
     self._solver_cache = {}
예제 #5
0
 def __add__(self, other):
     if not isinstance(other, (Minimize, Maximize)):
         return NotImplemented
     # Objectives must both be Minimize.
     if type(other) is Minimize:
         return Minimize(self.args[0] + other.args[0])
     else:
         raise DCPError("Problem does not follow DCP rules.")
 def __div__(self, other):
     """Expression : One expression divided by another.
     """
     # Can only divide by scalar constants.
     if other.is_constant() and other.is_scalar():
         return cvxtypes.div_expr()(self, other)
     else:
         raise DCPError("Can only divide by a scalar constant.")
예제 #7
0
	def apply(self, problem):
		inverse_data = InverseData(problem)
		is_minimize = type(problem.objective) == Minimize
		chance_expr, chance_constraints = self.chance_tree(problem.objective.args[0], is_minimize, True, False)
		chance_objective = Minimize(chance_expr) if is_minimize else Maximize(chance_expr)
		
		if any([type(atom) == cc.quantile for con in problem.constraints for atom in con.atoms()]):
			raise DCPError("Quantile atom may not be nested in constraints.")
		new_problem = cc.problem.Problem(chance_objective, problem.constraints + chance_constraints)
		return new_problem, inverse_data
예제 #8
0
파일: problem.py 프로젝트: msapy/chancecons
    def solve(self, *args, **kwargs):
        use_2step = kwargs.pop("two_step", True)
        use_slack = kwargs.pop("slack", False)

        # Reduce quantile atoms in objective.
        original = Problem(self._objective, self.constraints)
        if not Quantile2Chance().accepts(original):
            raise DCPError("Cannot convert quantiles to chance constraints")
        reduced, inv_data = Quantile2Chance().apply(original)

        # First pass with convex restrictions.
        chance_constraints = [
            cc for cc in reduced._chance_constraints if cc.fraction != 0
        ]
        for cc in chance_constraints:  # Define slack variable for each chance constraint.
            cc.slack = Variable(nonneg=True) if use_slack else 0
        restrictions = [cc.restriction for cc in chance_constraints]
        constrs1 = reduced._regular_constraints + restrictions
        prob1 = cvxprob.Problem(reduced.objective, constrs1)
        prob1.solve(*args, **kwargs)

        # Terminate if first pass does not produce solution.
        if prob1.status not in s.SOLUTION_PRESENT:
            self.save_results(prob1, [Quantile2Chance()], inv_data)
            raise SolverError("First pass failed with status {0}".format(
                self.status))

        if not use_2step:
            self.save_results(prob1, [Quantile2Chance()], inv_data)
            return self.value

        # Replace chance constraints with exact bounds where solution of
        # first pass yields a relatively low constraint violation.
        constrs2 = reduced._regular_constraints
        for cc in chance_constraints:
            subsets = self.best_subset(cc.margins(),
                                       (1.0 - cc.fraction) * cc.size)
            for constr, subset in zip(cc.constraints, subsets):
                # if not np.any(subset):
                #	continue
                if isinstance(constr, Inequality):
                    constrs2 += [constr.expr[subset] >= 0
                                 ]  # Flip direction of inequality.
                elif isinstance(constr, Equality):
                    constrs2 += [constr.expr[subset] == 0]
                else:
                    raise ValueError("Only (<=, ==, >=) constraints supported")

        # Second pass with exact bounds.
        prob2 = cvxprob.Problem(reduced.objective, constrs2)
        prob2.solve(*args, **kwargs)
        self.save_results(prob2, [Quantile2Chance()], inv_data)
        return self.value
예제 #9
0
	def chance_expr(self, expr, args, is_minimize, is_incr, is_decr):
		if type(expr) == cc.quantile:
			t = Variable(expr.shape)
			if (is_incr and is_minimize) or (is_decr and not is_minimize):
				constr = expr <= t   # TODO: Do we need expr.copy(args) here?
			elif (is_incr and not is_minimize) or (is_decr and is_minimize):
				constr = expr >= t
			else:
				raise DCPError("Objective must be non-decreasing or non-increasing in each quantile argument.")
			return t, [constr]
		else:
			return expr.copy(args), []
예제 #10
0
 def __init__(self, objective, constraints=None):
     if constraints is None:
         constraints = []
     # Check that objective is Minimize or Maximize.
     if not isinstance(objective, (Minimize, Maximize)):
         raise DCPError("Problem objective must be Minimize or Maximize.")
     # Constraints and objective are immutable.
     self.objective = objective
     self.constraints = constraints
     self._value = None
     self._status = None
     # Cached processed data for each solver.
     self._cached_data = {}
     self._reset_cache()
예제 #11
0
 def __init__(self, objective, constraints=None):
     if constraints is None:
         constraints = []
     # Check that objective is Minimize or Maximize.
     if not isinstance(objective, (Minimize, Maximize)):
         raise DCPError("Problem objective must be Minimize or Maximize.")
     # Constraints and objective are immutable.
     self.objective = objective
     self.constraints = constraints
     self._value = None
     self._status = None
     # Cached processed data for each solver.
     self._cached_data = {}
     self._reset_cache()
     # List of separable (sub)problems
     self._separable_problems = None
     # Information about the size of the problem and its constituent parts
     self._size_metrics = SizeMetrics(self)
예제 #12
0
파일: expression.py 프로젝트: giserh/cvxpy
 def __mul__(self, other):
     """The product of two expressions.
     """
     # Cannot multiply two non-constant expressions.
     if not self.is_constant() and \
        not other.is_constant():
         raise DCPError("Cannot multiply two non-constants.")
     # Multiplying by a constant on the right is handled differently
     # from multiplying by a constant on the left.
     elif self.is_constant():
         # TODO HACK catch c.T*x where c is a NumPy 1D array.
         if self.size[0] == other.size[0] and \
            self.size[1] != self.size[0] and \
            isinstance(self, types.constant()) and self.is_1D_array:
             self = self.T
         return types.mul_expr()(self, other)
     # Having the constant on the left is more efficient.
     elif self.is_scalar() or other.is_scalar():
         return types.mul_expr()(other, self)
     else:
         return types.rmul_expr()(self, other)
예제 #13
0
def construct_solving_chain(problem, solver=None):
    """Build a reduction chain from a problem to an installed solver.

    Note that if the supplied problem has 0 variables, then the solver
    parameter will be ignored.

    Parameters
    ----------
    problem : Problem
        The problem for which to build a chain.
    solver : string
        The name of the solver with which to terminate the chain. If no solver
        is supplied (i.e., if solver is None), then the targeted solver may be
        any of those that are installed. If the problem is variable-free,
        then this parameter is ignored.

    Returns
    -------
    SolvingChain
        A SolvingChain that can be used to solve the problem.

    Raises
    ------
    DCPError
        Raised if the problem is not DCP.
    SolverError
        Raised if no suitable solver exists among the installed solvers, or
        if the target solver is not installed.
    """
    if solver is not None:
        if solver not in INSTALLED_SOLVERS:
            raise SolverError("The solver %s is not installed." % solver)
        candidates = [solver]
    else:
        candidates = INSTALLED_SOLVERS

    reductions = []
    # Evaluate parameters and short-circuit the solver if the problem
    # is constant.
    if problem.parameters():
        reductions += [EvalParams()]
    if len(problem.variables()) == 0:
        reductions += [ConstantSolver()]
        return SolvingChain(reductions=reductions)
    if Complex2Real().accepts(problem):
        reductions += [Complex2Real()]

    #  Presently, we have but two reduction chains:
    #   (1) Qp2SymbolicQp --> QpMatrixStuffing --> [a QpSolver],
    #   (2) Dcp2Cone --> ConeMatrixStuffing --> [a ConicSolver]
    # Both of these chains require that the problem is DCP.
    if not problem.is_dcp():
        raise DCPError("Problem does not follow DCP rules.")

    # Both reduction chains exclusively accept minimization problems.
    if type(problem.objective) == Maximize:
        reductions.append(FlipObjective())

    # Attempt to canonicalize the problem to a linearly constrained QP.
    candidate_qp_solvers = [s for s in QP_SOLVERS if s in candidates]
    # Consider only MIQP solvers if problem is integer
    if problem.is_mixed_integer():
        candidate_qp_solvers = \
            [s for s in candidate_qp_solvers if
             SOLVER_MAP_QP[s].MIP_CAPABLE]
    if candidate_qp_solvers and Qp2SymbolicQp().accepts(problem):
        solver = sorted(candidate_qp_solvers,
                        key=lambda s: QP_SOLVERS.index(s))[0]
        solver_instance = SOLVER_MAP_QP[solver]
        reductions += [
            CvxAttr2Constr(),
            Qp2SymbolicQp(),
            QpMatrixStuffing(), solver_instance
        ]
        return SolvingChain(reductions=reductions)

    candidate_conic_solvers = [s for s in CONIC_SOLVERS if s in candidates]
    if problem.is_mixed_integer():
        candidate_conic_solvers = \
            [s for s in candidate_conic_solvers if
             SOLVER_MAP_CONIC[s].MIP_CAPABLE]
        if not candidate_conic_solvers and \
                not candidate_qp_solvers:
            raise SolverError("Problem is mixed-integer, but candidate "
                              "QP/Conic solvers (%s) are not MIP-capable." %
                              [candidate_qp_solvers, candidate_conic_solvers])
    if not candidate_conic_solvers:
        raise SolverError("Problem could not be reduced to a QP, and no "
                          "conic solvers exist among candidate solvers "
                          "(%s)." % candidates)

    # Attempt to canonicalize the problem to a cone program.
    # Our choice of solver depends upon which atoms are present in the
    # problem. The types of atoms to check for are SOC atoms, PSD atoms,
    # and exponential atoms.
    atoms = problem.atoms()
    cones = []
    if (any(atom in SOC_ATOMS for atom in atoms)
            or any(type(c) == SOC for c in problem.constraints)):
        cones.append(SOC)
    if (any(atom in EXP_ATOMS for atom in atoms)
            or any(type(c) == ExpCone for c in problem.constraints)):
        cones.append(ExpCone)
    if (any(atom in PSD_ATOMS for atom in atoms)
            or any(type(c) == PSD for c in problem.constraints)
            or any(v.is_psd() or v.is_nsd() for v in problem.variables())):
        cones.append(PSD)

    # Here, we make use of the observation that canonicalization only
    # increases the number of constraints in our problem.
    has_constr = len(cones) > 0 or len(problem.constraints) > 0

    for solver in sorted(candidate_conic_solvers,
                         key=lambda s: CONIC_SOLVERS.index(s)):
        solver_instance = SOLVER_MAP_CONIC[solver]
        if (all(c in solver_instance.SUPPORTED_CONSTRAINTS for c in cones)
                and (has_constr or not solver_instance.REQUIRES_CONSTR)):
            reductions += [
                Dcp2Cone(),
                CvxAttr2Constr(),
                ConeMatrixStuffing(), solver_instance
            ]
            return SolvingChain(reductions=reductions)

    raise SolverError(
        "Either candidate conic solvers (%s) do not support the "
        "cones output by the problem (%s), or there are not "
        "enough constraints in the problem." %
        (candidate_conic_solvers, ", ".join([cone.__name__
                                             for cone in cones])))
예제 #14
0
def construct_intermediate_chain(problem, candidates, gp: bool = False):
    """
    Builds a chain that rewrites a problem into an intermediate
    representation suitable for numeric reductions.

    Parameters
    ----------
    problem : Problem
        The problem for which to build a chain.
    candidates : dict
        Dictionary of candidate solvers divided in qp_solvers
        and conic_solvers.
    gp : bool
        If True, the problem is parsed as a Disciplined Geometric Program
        instead of as a Disciplined Convex Program.

    Returns
    -------
    Chain
        A Chain that can be used to convert the problem to an intermediate form.

    Raises
    ------
    DCPError
        Raised if the problem is not DCP and `gp` is False.
    DGPError
        Raised if the problem is not DGP and `gp` is True.
    """

    reductions = []
    if len(problem.variables()) == 0:
        return Chain(reductions=reductions)
    # TODO Handle boolean constraints.
    if complex2real.accepts(problem):
        reductions += [complex2real.Complex2Real()]
    if gp:
        reductions += [Dgp2Dcp()]

    if not gp and not problem.is_dcp():
        append = build_non_disciplined_error_msg(problem, 'DCP')
        if problem.is_dgp():
            append += ("\nHowever, the problem does follow DGP rules. "
                       "Consider calling solve() with `gp=True`.")
        elif problem.is_dqcp():
            append += ("\nHowever, the problem does follow DQCP rules. "
                       "Consider calling solve() with `qcp=True`.")
        raise DCPError("Problem does not follow DCP rules. Specifically:\n" +
                       append)

    elif gp and not problem.is_dgp():
        append = build_non_disciplined_error_msg(problem, 'DGP')
        if problem.is_dcp():
            append += ("\nHowever, the problem does follow DCP rules. "
                       "Consider calling solve() with `gp=False`.")
        elif problem.is_dqcp():
            append += ("\nHowever, the problem does follow DQCP rules. "
                       "Consider calling solve() with `qcp=True`.")
        raise DGPError("Problem does not follow DGP rules." + append)

    # Dcp2Cone and Qp2SymbolicQp require problems to minimize their objectives.
    if type(problem.objective) == Maximize:
        reductions += [FlipObjective()]

    # First, attempt to canonicalize the problem to a linearly constrained QP.
    if candidates['qp_solvers'] and qp2symbolic_qp.accepts(problem):
        reductions += [CvxAttr2Constr(), Qp2SymbolicQp()]
        return Chain(reductions=reductions)

    # Canonicalize it to conic problem.
    if not candidates['conic_solvers']:
        raise SolverError("Problem could not be reduced to a QP, and no "
                          "conic solvers exist among candidate solvers "
                          "(%s)." % candidates)
    reductions += [Dcp2Cone(), CvxAttr2Constr()]
    return Chain(reductions=reductions)
예제 #15
0
    def _solve(self,
               solver=None,
               ignore_dcp=False,
               warm_start=False,
               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
            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 not self.is_dcp():
            if ignore_dcp:
                print("Problem does not follow DCP rules. "
                      "Solving a convex relaxation.")
            else:
                raise DCPError("Problem does not follow DCP rules.")

        if solver == s.LS:
            solver = SOLVERS[s.LS]
            solver.validate_solver(self)

            objective = self.objective
            constraints = self.constraints

            sym_data = solver.get_sym_data(objective, constraints)
            results_dict = solver.solve(objective, constraints,
                                        self._cached_data, warm_start, verbose,
                                        kwargs)
            self._update_problem_state(results_dict, sym_data, solver)
            return self.value

        # Standard cone problem
        objective, constraints = self.canonicalize()

        # Solve in parallel
        if parallel:
            # Check if the objective or constraint has changed

            if (objective != self._cached_data[s.PARALLEL].objective or
                    constraints != self._cached_data[s.PARALLEL].constraints):
                self._separable_problems = cvxpy.transforms.get_separable_problems(
                    self)
                self._cached_data[s.PARALLEL] = CachedProblem(
                    objective, constraints)
            if len(self._separable_problems) > 1:
                return self._parallel_solve(solver, ignore_dcp, warm_start,
                                            verbose, **kwargs)

        # Choose a solver/check the chosen solver.
        if solver is None:
            solver_name = Solver.choose_solver(constraints)
            solver = SOLVERS[solver_name]
        elif solver in SOLVERS:
            solver = SOLVERS[solver]
            solver.validate_solver(constraints)
        else:
            raise SolverError("Unknown solver.")

        sym_data = solver.get_sym_data(objective, constraints,
                                       self._cached_data)
        # Presolve couldn't solve the problem.
        if sym_data.presolve_status is None:
            results_dict = solver.solve(objective, constraints,
                                        self._cached_data, warm_start, verbose,
                                        kwargs)
        # Presolve determined problem was unbounded or infeasible.
        else:
            results_dict = {s.STATUS: sym_data.presolve_status}
        self._update_problem_state(results_dict, sym_data, solver)
        return self.value
예제 #16
0
def construct_solving_chain(problem, solver=None, gp=False):
    """Build a reduction chain from a problem to an installed solver.

    Note that if the supplied problem has 0 variables, then the solver
    parameter will be ignored.

    Parameters
    ----------
    problem : Problem
        The problem for which to build a chain.
    solver : string
        The name of the solver with which to terminate the chain. If no solver
        is supplied (i.e., if solver is None), then the targeted solver may be
        any of those that are installed. If the problem is variable-free,
        then this parameter is ignored.
    gp : bool
        If True, the problem is parsed as a Disciplined Geometric Program
        instead of as a Disciplined Convex Program.

    Returns
    -------
    SolvingChain
        A SolvingChain that can be used to solve the problem.

    Raises
    ------
    DCPError
        Raised if the problem is not DCP and `gp` is False.
    DGPError
        Raised if the problem is not DGP and `gp` is True.
    SolverError
        Raised if no suitable solver exists among the installed solvers, or
        if the target solver is not installed.
    """
    if solver is not None:
        if solver not in slv_def.INSTALLED_SOLVERS:
            raise SolverError("The solver %s is not installed." % solver)
        candidates = [solver]
    else:
        candidates = slv_def.INSTALLED_SOLVERS

    reductions = []
    if problem.parameters():
        reductions += [EvalParams()]
    if len(problem.variables()) == 0:
        reductions += [ConstantSolver()]
        return SolvingChain(reductions=reductions)
    if Complex2Real().accepts(problem):
        reductions += [Complex2Real()]
    if gp:
        reductions += [Dgp2Dcp()]
        if solver is not None and solver not in slv_def.CONIC_SOLVERS:
            raise SolverError(
                "When `gp=True`, `solver` must be a conic solver "
                "(received '%s'); try calling `solve()` with `solver=cvxpy.ECOS`."
                % solver)
        elif solver is None:
            candidates = slv_def.INSTALLED_CONIC_SOLVERS

    if not gp and not problem.is_dcp():
        append = ""
        if problem.is_dgp():
            append = (" However, the problem does follow DGP rules. "
                      "Consider calling this function with `gp=True`.")
        raise DCPError("Problem does not follow DCP rules." + append)
    elif gp and not problem.is_dgp():
        append = ""
        if problem.is_dcp():
            append = (" However, the problem does follow DCP rules. "
                      "Consider calling this function with `gp=False`.")
        raise DGPError("Problem does not follow DGP rules." + append)

    # Dcp2Cone and Qp2SymbolicQp require problems to minimize their objectives.
    if type(problem.objective) == Maximize:
        reductions.append(FlipObjective())

    # Conclude the chain with one of the following:
    #   (1) Qp2SymbolicQp --> QpMatrixStuffing --> [a QpSolver],
    #   (2) Dcp2Cone --> ConeMatrixStuffing --> [a ConicSolver]
    #
    # First, attempt to canonicalize the problem to a linearly constrained QP.
    candidate_qp_solvers = [s for s in slv_def.QP_SOLVERS if s in candidates]
    # Consider only MIQP solvers if problem is integer
    if problem.is_mixed_integer():
        candidate_qp_solvers = [
            s for s in candidate_qp_solvers
            if slv_def.SOLVER_MAP_QP[s].MIP_CAPABLE
        ]
    if candidate_qp_solvers and Qp2SymbolicQp().accepts(problem):
        solver = sorted(candidate_qp_solvers,
                        key=lambda s: slv_def.QP_SOLVERS.index(s))[0]
        solver_instance = slv_def.SOLVER_MAP_QP[solver]
        reductions += [
            CvxAttr2Constr(),
            Qp2SymbolicQp(),
            QpMatrixStuffing(), solver_instance
        ]
        return SolvingChain(reductions=reductions)

    candidate_conic_solvers = [
        s for s in slv_def.CONIC_SOLVERS if s in candidates
    ]
    if problem.is_mixed_integer():
        candidate_conic_solvers = \
            [s for s in candidate_conic_solvers if
             slv_def.SOLVER_MAP_CONIC[s].MIP_CAPABLE]
        if not candidate_conic_solvers and \
                not candidate_qp_solvers:
            raise SolverError("Problem is mixed-integer, but candidate "
                              "QP/Conic solvers (%s) are not MIP-capable." %
                              [candidate_qp_solvers, candidate_conic_solvers])
    if not candidate_conic_solvers:
        raise SolverError("Problem could not be reduced to a QP, and no "
                          "conic solvers exist among candidate solvers "
                          "(%s)." % candidates)

    # Attempt to canonicalize the problem to a cone program.
    # Our choice of solver depends upon which atoms are present in the
    # problem. The types of atoms to check for are SOC atoms, PSD atoms,
    # and exponential atoms.
    atoms = problem.atoms()
    cones = []
    if (any(atom in SOC_ATOMS for atom in atoms)
            or any(type(c) == SOC for c in problem.constraints)):
        cones.append(SOC)
    if (any(atom in EXP_ATOMS for atom in atoms)
            or any(type(c) == ExpCone for c in problem.constraints)):
        cones.append(ExpCone)
    if (any(atom in PSD_ATOMS for atom in atoms)
            or any(type(c) == PSD for c in problem.constraints)
            or any(v.is_psd() or v.is_nsd() for v in problem.variables())):
        cones.append(PSD)

    # Here, we make use of the observation that canonicalization only
    # increases the number of constraints in our problem.
    has_constr = len(cones) > 0 or len(problem.constraints) > 0

    for solver in sorted(candidate_conic_solvers,
                         key=lambda s: slv_def.CONIC_SOLVERS.index(s)):
        solver_instance = slv_def.SOLVER_MAP_CONIC[solver]
        if (all(c in solver_instance.SUPPORTED_CONSTRAINTS for c in cones)
                and (has_constr or not solver_instance.REQUIRES_CONSTR)):
            reductions += [
                Dcp2Cone(),
                CvxAttr2Constr(),
                ConeMatrixStuffing(), solver_instance
            ]
            return SolvingChain(reductions=reductions)

    raise SolverError(
        "Either candidate conic solvers (%s) do not support the "
        "cones output by the problem (%s), or there are not "
        "enough constraints in the problem." %
        (candidate_conic_solvers, ", ".join([cone.__name__
                                             for cone in cones])))
예제 #17
0
파일: problem.py 프로젝트: giserh/cvxpy
    def _solve(self, solver=None, ignore_dcp=False,
               warm_start=False, verbose=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
            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.
        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 not self.is_dcp() and not ignore_dcp: #if not DCP and not ignore
            #if self.is_dccp():
            #    print("Problem does not follow DCP rules, but follows DCCP rules")
            #    result = self.DCCP(solver,**kwargs)
            #    return(result)
            #else:
            raise DCPError("Problem does not follow DCP rules.")
        else: # is DCP or ignore
            if ignore_dcp and not self.dcp():
                print ("Problem does not follow DCP rules. "
                       "Solving a convex relaxation.")
            objective, constraints = self.canonicalize()
            # Choose a solver/check the chosen solver.
            if solver is None:
                solver_name = Solver.choose_solver(constraints)
                solver = SOLVERS[solver_name]
            elif solver in SOLVERS:
                solver = SOLVERS[solver]
                solver.validate_solver(constraints)
            else:
                raise SolverError("Unknown solver.")

            sym_data = solver.get_sym_data(objective, constraints,
                                       self._cached_data)
            # Presolve couldn't solve the problem.
            if sym_data.presolve_status is None:
                results_dict = solver.solve(objective, constraints,
                                        self._cached_data,
                                        warm_start, verbose, kwargs)
            # Presolve determined problem was unbounded or infeasible.
            else:
                results_dict = {s.STATUS: sym_data.presolve_status}

            self._update_problem_state(results_dict, sym_data, solver)
            return self.value
예제 #18
0
def _reductions_for_problem_class(problem,
                                  candidates,
                                  gp: bool = False) -> List[Any]:
    """
    Builds a chain that rewrites a problem into an intermediate
    representation suitable for numeric reductions.

    Parameters
    ----------
    problem : Problem
        The problem for which to build a chain.
    candidates : dict
        Dictionary of candidate solvers divided in qp_solvers
        and conic_solvers.
    gp : bool
        If True, the problem is parsed as a Disciplined Geometric Program
        instead of as a Disciplined Convex Program.
    Returns
    -------
    list of Reduction objects
        A list of reductions that can be used to convert the problem to an
        intermediate form.
    Raises
    ------
    DCPError
        Raised if the problem is not DCP and `gp` is False.
    DGPError
        Raised if the problem is not DGP and `gp` is True.
    """
    reductions = []
    # TODO Handle boolean constraints.
    if complex2real.accepts(problem):
        reductions += [complex2real.Complex2Real()]
    if gp:
        reductions += [Dgp2Dcp()]

    if not gp and not problem.is_dcp():
        append = build_non_disciplined_error_msg(problem, 'DCP')
        if problem.is_dgp():
            append += ("\nHowever, the problem does follow DGP rules. "
                       "Consider calling solve() with `gp=True`.")
        elif problem.is_dqcp():
            append += ("\nHowever, the problem does follow DQCP rules. "
                       "Consider calling solve() with `qcp=True`.")
        raise DCPError("Problem does not follow DCP rules. Specifically:\n" +
                       append)
    elif gp and not problem.is_dgp():
        append = build_non_disciplined_error_msg(problem, 'DGP')
        if problem.is_dcp():
            append += ("\nHowever, the problem does follow DCP rules. "
                       "Consider calling solve() with `gp=False`.")
        elif problem.is_dqcp():
            append += ("\nHowever, the problem does follow DQCP rules. "
                       "Consider calling solve() with `qcp=True`.")
        raise DGPError("Problem does not follow DGP rules." + append)

    # Dcp2Cone and Qp2SymbolicQp require problems to minimize their objectives.
    if type(problem.objective) == Maximize:
        reductions += [FlipObjective()]

    if _solve_as_qp(problem, candidates):
        reductions += [CvxAttr2Constr(), qp2symbolic_qp.Qp2SymbolicQp()]
    else:
        # Canonicalize it to conic problem.
        if not candidates['conic_solvers']:
            raise SolverError("Problem could not be reduced to a QP, and no "
                              "conic solvers exist among candidate solvers "
                              "(%s)." % candidates)
        else:
            reductions += [Dcp2Cone(), CvxAttr2Constr()]

    constr_types = {type(c) for c in problem.constraints}
    if FiniteSet in constr_types:
        reductions += [Valinvec2mixedint()]

    return reductions