def test_psd_constraints(self): """ Test positive semi-definite constraints """ C = Variable((3, 3)) obj = Maximize(C[0, 2]) constraints = [ diag(C) == 1, C[0, 1] == 0.6, C[1, 2] == -0.3, C == C.T, C >> 0 ] prob = Problem(obj, constraints) self.assertTrue(FlipObjective().accepts(prob)) p_min = FlipObjective().apply(prob) self.assertTrue(ConeMatrixStuffing().accepts(p_min[0])) C = Variable((2, 2)) obj = Maximize(C[0, 1]) constraints = [C == 1, C >> [[2, 0], [0, 2]]] prob = Problem(obj, constraints) self.assertTrue(FlipObjective().accepts(prob)) p_min = FlipObjective().apply(prob) self.assertTrue(ConeMatrixStuffing().accepts(p_min[0])) C = Variable((2, 2), symmetric=True) obj = Minimize(C[0, 0]) constraints = [C << [[2, 0], [0, 2]]] prob, _ = CvxAttr2Constr().apply(Problem(obj, constraints)) self.assertTrue(ConeMatrixStuffing().accepts(prob))
def test_nonneg_constraints_backend(self) -> None: x = Variable(shape=(2, ), name='x') objective = Maximize(-4 * x[0] - 5 * x[1]) constr_expr = hstack( [3 - (2 * x[0] + x[1]), 3 - (x[0] + 2 * x[1]), x[0], x[1]]) constraints = [NonNeg(constr_expr)] prob = Problem(objective, constraints) self.assertFalse(ConeMatrixStuffing().accepts(prob)) self.assertTrue(FlipObjective().accepts(prob)) p_min = FlipObjective().apply(prob) self.assertTrue(ConeMatrixStuffing().accepts(p_min[0]))
def simulate_chain(in_prob, affine, **solve_kwargs): # get a ParamConeProg object reductions = [Dcp2Cone(), CvxAttr2Constr(), ConeMatrixStuffing()] chain = Chain(None, reductions) cone_prog, inv_prob2cone = chain.apply(in_prob) # apply the Slacks reduction, reconstruct a high-level problem, # solve the problem, invert the reduction. cone_prog = ConicSolver().format_constraints(cone_prog, exp_cone_order=[0, 1, 2]) data, inv_data = a2d.Slacks.apply(cone_prog, affine) G, h, f, K_dir, K_aff = data[s.A], data[s.B], data[ s.C], data['K_dir'], data['K_aff'] G = sp.sparse.csc_matrix(G) y = cp.Variable(shape=(G.shape[1], )) objective = cp.Minimize(f @ y) aff_con = TestSlacks.set_affine_constraints(G, h, y, K_aff) dir_con = TestSlacks.set_direct_constraints(y, K_dir) int_con = TestSlacks.set_integer_constraints(y, data) constraints = aff_con + dir_con + int_con slack_prob = cp.Problem(objective, constraints) slack_prob.solve(**solve_kwargs) slack_prims = { a2d.FREE: y[:cone_prog.x.size].value } # nothing else need be populated. slack_sol = cp.Solution(slack_prob.status, slack_prob.value, slack_prims, None, dict()) cone_sol = a2d.Slacks.invert(slack_sol, inv_data) # pass solution up the solving chain in_prob_sol = chain.invert(cone_sol, inv_prob2cone) in_prob.unpack(in_prob_sol)
def test_matrix_lp(self): for solver in self.solvers: T = Constant(numpy.ones((2, 2))).value p = Problem(Minimize(1 + self.a), [self.A == T + self.a, self.a >= 0]) self.assertTrue(ConeMatrixStuffing().accepts(p)) result = p.solve(solver.name()) p_new = ConeMatrixStuffing().apply(p) sltn = solver.solve(p_new[0], False, False, {}) self.assertAlmostEqual(sltn.opt_val, result - 1) inv_sltn = ConeMatrixStuffing().invert(sltn, p_new[1]) self.assertAlmostEqual(inv_sltn.opt_val, result) for var in p.variables(): self.assertItemsAlmostEqual(inv_sltn.primal_vars[var.id], var.value) T = Constant(numpy.ones((2, 3)) * 2).value p = Problem( Minimize(1), [self.A >= T * self.C, self.A == self.B, self.C == T.T]) self.assertTrue(ConeMatrixStuffing().accepts(p)) result = p.solve(solver.name()) p_new = ConeMatrixStuffing().apply(p) sltn = solver.solve(p_new[0], False, False, {}) self.assertAlmostEqual(sltn.opt_val, result - 1) inv_sltn = ConeMatrixStuffing().invert(sltn, p_new[1]) self.assertAlmostEqual(inv_sltn.opt_val, result) for var in p.variables(): self.assertItemsAlmostEqual(inv_sltn.primal_vars[var.id], var.value)
def exp_cone(self): """Test exponential cone problems. """ for solver in self.solvers: # Basic. p = Problem(Minimize(self.b), [exp(self.a) <= self.b, self.a >= 1]) pmod = Problem(Minimize(self.b), [ExpCone(self.a, Constant(1), self.b), self.a >= 1]) self.assertTrue(ConeMatrixStuffing().accepts(pmod)) p_new = ConeMatrixStuffing().apply(pmod) if not solver.accepts(p_new[0]): return result = p.solve(solver.name()) sltn = solve_wrapper(solver, p_new[0]) self.assertAlmostEqual(sltn.opt_val, result, places=1) inv_sltn = ConeMatrixStuffing().invert(sltn, p_new[1]) self.assertAlmostEqual(inv_sltn.opt_val, result, places=1) for var in pmod.variables(): self.assertItemsAlmostEqual(inv_sltn.primal_vars[var.id], var.value, places=1) # More complex. p = Problem(Minimize(self.b), [exp(self.a/2 + self.c) <= self.b+5, self.a >= 1, self.c >= 5]) pmod = Problem(Minimize(self.b), [ExpCone(self.a/2 + self.c, Constant(1), self.b+5), self.a >= 1, self.c >= 5]) self.assertTrue(ConeMatrixStuffing().accepts(pmod)) result = p.solve(solver.name()) p_new = ConeMatrixStuffing().apply(pmod) sltn = solve_wrapper(solver, p_new[0]) self.assertAlmostEqual(sltn.opt_val, result, places=0) inv_sltn = ConeMatrixStuffing().invert(sltn, p_new[1]) self.assertAlmostEqual(inv_sltn.opt_val, result, places=0) for var in pmod.variables(): self.assertItemsAlmostEqual(inv_sltn.primal_vars[var.id], var.value, places=0)
def test_socp(self): """Test SOCP problems. """ for solver in self.solvers: # Basic. p = Problem(Minimize(self.b), [pnorm(self.x, p=2) <= self.b]) pmod = Problem(Minimize(self.b), [SOC(self.b, self.x)]) self.assertTrue(ConeMatrixStuffing().accepts(pmod)) p_new = ConeMatrixStuffing().apply(pmod) if not solver.accepts(p_new[0]): return result = p.solve(solver.name()) sltn = solve_wrapper(solver, p_new[0]) self.assertAlmostEqual(sltn.opt_val, result) inv_sltn = ConeMatrixStuffing().invert(sltn, p_new[1]) self.assertAlmostEqual(inv_sltn.opt_val, result) for var in p.variables(): self.assertItemsAlmostEqual(inv_sltn.primal_vars[var.id], var.value) # More complex. p = Problem(Minimize(self.b), [pnorm(self.x/2 + self.y[:2], p=2) <= self.b+5, self.x >= 1, self.y == 5]) pmod = Problem(Minimize(self.b), [SOC(self.b+5, self.x/2 + self.y[:2]), self.x >= 1, self.y == 5]) self.assertTrue(ConeMatrixStuffing().accepts(pmod)) result = p.solve(solver.name()) p_new = ConeMatrixStuffing().apply(pmod) sltn = solve_wrapper(solver, p_new[0]) self.assertAlmostEqual(sltn.opt_val, result, places=2) inv_sltn = ConeMatrixStuffing().invert(sltn, p_new[1]) self.assertAlmostEqual(inv_sltn.opt_val, result, places=2) for var in p.variables(): self.assertItemsAlmostEqual(inv_sltn.primal_vars[var.id], var.value, places=2)
def simulate_chain(in_prob): # Get a ParamConeProg object reductions = [Dcp2Cone(), CvxAttr2Constr(), ConeMatrixStuffing()] chain = Chain(None, reductions) cone_prog, inv_prob2cone = chain.apply(in_prob) # Dualize the problem, reconstruct a high-level cvxpy problem for the dual. # Solve the problem, invert the dualize reduction. solver = ConicSolver() cone_prog = solver.format_constraints(cone_prog, exp_cone_order=[0, 1, 2]) data, inv_data = a2d.Dualize.apply(cone_prog) A, b, c, K_dir = data[s.A], data[s.B], data[s.C], data['K_dir'] y = cp.Variable(shape=(A.shape[1], )) constraints = [A @ y == b] i = K_dir[a2d.FREE] dual_prims = {a2d.FREE: y[:i], a2d.SOC: []} if K_dir[a2d.NONNEG]: dim = K_dir[a2d.NONNEG] dual_prims[a2d.NONNEG] = y[i:i + dim] constraints.append(y[i:i + dim] >= 0) i += dim for dim in K_dir[a2d.SOC]: dual_prims[a2d.SOC].append(y[i:i + dim]) constraints.append(SOC(y[i], y[i + 1:i + dim])) i += dim if K_dir[a2d.DUAL_EXP]: dual_prims[a2d.DUAL_EXP] = y[i:] y_de = cp.reshape(y[i:], ((y.size - i) // 3, 3), order='C') # fill rows first constraints.append( ExpCone(-y_de[:, 1], -y_de[:, 0], np.exp(1) * y_de[:, 2])) objective = cp.Maximize(c @ y) dual_prob = cp.Problem(objective, constraints) dual_prob.solve(solver='SCS', eps=1e-8) dual_prims[a2d.FREE] = dual_prims[a2d.FREE].value if K_dir[a2d.NONNEG]: dual_prims[a2d.NONNEG] = dual_prims[a2d.NONNEG].value dual_prims[a2d.SOC] = [expr.value for expr in dual_prims[a2d.SOC]] if K_dir[a2d.DUAL_EXP]: dual_prims[a2d.DUAL_EXP] = dual_prims[a2d.DUAL_EXP].value dual_duals = {s.EQ_DUAL: constraints[0].dual_value} dual_sol = cp.Solution(dual_prob.status, dual_prob.value, dual_prims, dual_duals, dict()) cone_sol = a2d.Dualize.invert(dual_sol, inv_data) # Pass the solution back up the solving chain. in_prob_sol = chain.invert(cone_sol, inv_prob2cone) in_prob.unpack(in_prob_sol)
def test_vector_lp(self): for solver in self.solvers: c = Constant(numpy.array([1, 2])) p = Problem(Minimize(c.T * self.x), [self.x >= c]) result = p.solve(solver.name()) self.assertTrue(ConeMatrixStuffing().accepts(p)) p_new = ConeMatrixStuffing().apply(p) # result_new = p_new[0].solve(solver.name()) # self.assertAlmostEqual(result, result_new) self.assertTrue(solver.accepts(p_new[0])) sltn = solver.solve(p_new[0], False, False, {}) self.assertAlmostEqual(sltn.opt_val, result) inv_sltn = ConeMatrixStuffing().invert(sltn, p_new[1]) p_new1 = ConeMatrixStuffing().apply(p) self.assertTrue(solver.accepts(p_new1[0])) sltn = solver.solve(p_new1[0], False, False, {}) self.assertAlmostEqual(sltn.opt_val, result) inv_sltn = ConeMatrixStuffing().invert(sltn, p_new1[1]) self.assertAlmostEqual(inv_sltn.opt_val, result) self.assertItemsAlmostEqual(inv_sltn.primal_vars[self.x.id], self.x.value) A = Constant(numpy.array([[3, 5], [1, 2]]).T).value Imat = Constant([[1, 0], [0, 1]]) p = Problem(Minimize(c.T * self.x + self.a), [ A * self.x >= [-1, 1], 4 * Imat * self.z == self.x, self.z >= [2, 2], self.a >= 2 ]) self.assertTrue(ConeMatrixStuffing().accepts(p)) result = p.solve(solver.name()) p_new = ConeMatrixStuffing().apply(p) result_new = p_new[0].solve(solver.name()) self.assertAlmostEqual(result, result_new) self.assertTrue(solver.accepts(p_new[0])) sltn = solver.solve(p_new[0], False, False, {}) self.assertAlmostEqual(sltn.opt_val, result, places=1) inv_sltn = ConeMatrixStuffing().invert(sltn, p_new[1]) self.assertAlmostEqual(inv_sltn.opt_val, result, places=1) for var in p.variables(): self.assertItemsAlmostEqual(inv_sltn.primal_vars[var.id], var.value, places=1)
def small_parameterized_cone_matrix_stuffing(): ConeMatrixStuffing().apply(problem)
def small_cone_matrix_stuffing(): ConeMatrixStuffing().apply(problem)
def cone_matrix_stuffing_with_many_constraints(): ConeMatrixStuffing().apply(problem)
def test_scalar_lp(self): """Test scalar LP problems. """ for solver in self.solvers: p = Problem(Minimize(3 * self.a), [self.a >= 2]) self.assertTrue(ConeMatrixStuffing().accepts(p)) result = p.solve(solver.name()) p_new = ConeMatrixStuffing().apply(p) result_new = p_new[0].solve(solver.name()) self.assertAlmostEqual(result, result_new) sltn = solver.solve(p_new[0], False, False, {}) self.assertAlmostEqual(sltn.opt_val, result) inv_sltn = ConeMatrixStuffing().invert(sltn, p_new[1]) self.assertAlmostEqual(inv_sltn.opt_val, result) self.assertAlmostEqual(inv_sltn.primal_vars[self.a.id], self.a.value) # TODO: Maximize p = Problem(Minimize(-3 * self.a + self.b), [self.a <= 2, self.b == self.a, self.b <= 5]) result = p.solve(solver.name()) self.assertTrue(ConeMatrixStuffing().accepts(p)) p_new = ConeMatrixStuffing().apply(p) sltn = solver.solve(p_new[0], False, False, {}) self.assertAlmostEqual(sltn.opt_val, result) inv_sltn = ConeMatrixStuffing().invert(sltn, p_new[1]) self.assertAlmostEqual(inv_sltn.opt_val, result) self.assertAlmostEqual(inv_sltn.primal_vars[self.a.id], self.a.value) self.assertAlmostEqual(inv_sltn.primal_vars[self.b.id], self.b.value) # With a constant in the objective. p = Problem(Minimize(3 * self.a - self.b + 100), [ self.a >= 2, self.b + 5 * self.c - 2 == self.a, self.b <= 5 + self.c ]) self.assertTrue(ConeMatrixStuffing().accepts(p)) result = p.solve(solver.name()) p_new = ConeMatrixStuffing().apply(p) sltn = solver.solve(p_new[0], False, False, {}) self.assertAlmostEqual(sltn.opt_val, result - 100) inv_sltn = ConeMatrixStuffing().invert(sltn, p_new[1]) self.assertAlmostEqual(inv_sltn.opt_val, result) self.assertAlmostEqual(inv_sltn.primal_vars[self.a.id], self.a.value) self.assertAlmostEqual(inv_sltn.primal_vars[self.b.id], self.b.value) # Unbounded problems. # TODO: Maximize p = Problem(Minimize(-self.a), [self.a >= 2]) self.assertTrue(ConeMatrixStuffing().accepts(p)) try: result = p.solve(solver.name()) except SolverError: # Gurobi fails on this one return p_new = ConeMatrixStuffing().apply(p) self.assertTrue(solver.accepts(p_new[0])) sltn = solver.solve(p_new[0], False, False, {}) self.assertAlmostEqual(sltn.opt_val, result) inv_sltn = ConeMatrixStuffing().invert(sltn, p_new[1]) self.assertAlmostEqual(inv_sltn.opt_val, result) # Infeasible problems. p = Problem(Maximize(self.a), [self.a >= 2, self.a <= 1]) result = p.solve(solver.name()) self.assertTrue(FlipObjective().accepts(p)) p_min = FlipObjective().apply(p) self.assertTrue(ConeMatrixStuffing().accepts(p_min[0])) p_new = ConeMatrixStuffing().apply(p_min[0]) result_new = p_new[0].solve(solver.name()) self.assertAlmostEqual(result, -result_new) self.assertTrue(solver.accepts(p_new[0])) sltn = solver.solve(p_new[0], False, False, {}) self.assertAlmostEqual(sltn.opt_val, -result) inv_sltn = ConeMatrixStuffing().invert(sltn, p_new[1]) self.assertAlmostEqual(inv_sltn.opt_val, -result) inv_flipped_sltn = FlipObjective().invert(inv_sltn, p_min[1]) self.assertAlmostEqual(inv_flipped_sltn.opt_val, result)
def construct_solving_chain(problem, candidates, gp: bool = False, enforce_dpp: bool = False) -> "SolvingChain": """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. 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. enforce_dpp : bool, optional When True, a DPPError will be thrown when trying to parse a non-DPP problem (instead of just a warning). Defaults to False. Returns ------- SolvingChain A SolvingChain that can be used to solve the problem. Raises ------ SolverError Raised if no suitable solver exists among the installed solvers, or if the target solver is not installed. """ if len(problem.variables()) == 0: return SolvingChain(reductions=[ConstantSolver()]) reductions = _reductions_for_problem_class(problem, candidates, gp) dpp_context = 'dcp' if not gp else 'dgp' dpp_error_msg = ( "You are solving a parameterized problem that is not DPP. " "Because the problem is not DPP, subsequent solves will not be " "faster than the first one. For more information, see the " "documentation on Discplined Parametrized Programming, at\n" "\thttps://www.cvxpy.org/tutorial/advanced/index.html#" "disciplined-parametrized-programming") if not problem.is_dpp(dpp_context): if not enforce_dpp: warnings.warn(dpp_error_msg) reductions = [EvalParams()] + reductions else: raise DPPError(dpp_error_msg) elif any(param.is_complex() for param in problem.parameters()): reductions = [EvalParams()] + reductions # Conclude with matrix stuffing; choose one of the following paths: # (1) QpMatrixStuffing --> [a QpSolver], # (2) ConeMatrixStuffing --> [a ConicSolver] if _solve_as_qp(problem, candidates): # Canonicalize as a QP solver = candidates['qp_solvers'][0] solver_instance = slv_def.SOLVER_MAP_QP[solver] reductions += [QpMatrixStuffing(), solver_instance] return SolvingChain(reductions=reductions) # Canonicalize as a cone program 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) constr_types = set() # ^ We use constr_types to infer an incomplete list of cones that # the solver will need after canonicalization. for c in problem.constraints: constr_types.add(type(c)) ex_cos = [ct for ct in constr_types if ct in EXOTIC_CONES] # ^ The way we populate "ex_cos" will need to change if and when # we have atoms that require exotic cones. for co in ex_cos: sim_cos = EXOTIC_CONES[co] # get the set of required simple cones constr_types.update(sim_cos) constr_types.remove(co) # We now go over individual elementary cones support by CVXPY ( # SOC, ExpCone, NonNeg, Zero, PSD, PowCone3D) and check if # they've appeared in constr_types or if the problem has an atom # requiring that cone. cones = [] atoms = problem.atoms() if SOC in constr_types or any(atom in SOC_ATOMS for atom in atoms): cones.append(SOC) if ExpCone in constr_types or any(atom in EXP_ATOMS for atom in atoms): cones.append(ExpCone) if any(t in constr_types for t in [Inequality, NonPos, NonNeg]) \ or any(atom in NONPOS_ATOMS for atom in atoms): cones.append(NonNeg) if Equality in constr_types or Zero in constr_types: cones.append(Zero) if PSD in constr_types \ or any(atom in PSD_ATOMS for atom in atoms) \ or any(v.is_psd() or v.is_nsd() for v in problem.variables()): cones.append(PSD) if PowCone3D in constr_types: # if we add in atoms that specifically use the 3D power cone # (rather than the ND power cone), then we'll need to check # for those atoms here as well. cones.append(PowCone3D) # 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 candidates['conic_solvers']: 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)): if ex_cos: reductions.append(Exotic2Common()) reductions += [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." % ( candidates['conic_solvers'], ", ".join([cone.__name__ for cone in cones])))
def construct_solving_chain(problem, candidates, gp=False, enforce_dpp=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. 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. enforce_dpp : bool, optional When True, a DPPError will be thrown when trying to parse a non-DPP problem (instead of just a warning). Defaults to False. Returns ------- SolvingChain A SolvingChain that can be used to solve the problem. Raises ------ SolverError Raised if no suitable solver exists among the installed solvers, or if the target solver is not installed. """ if len(problem.variables()) == 0: return SolvingChain(reductions=[ConstantSolver()]) reductions = _reductions_for_problem_class(problem, candidates, gp) dpp_context = 'dcp' if not gp else 'dgp' dpp_error_msg = ( "You are solving a parameterized problem that is not DPP. " "Because the problem is not DPP, subsequent solves will not be " "faster than the first one. For more information, see the " "documentation on Discplined Parametrized Programming, at\n" "\thttps://www.cvxpy.org/tutorial/advanced/index.html#" "disciplined-parametrized-programming") if not problem.is_dpp(dpp_context): if not enforce_dpp: warnings.warn(dpp_error_msg) reductions = [EvalParams()] + reductions else: raise DPPError(dpp_error_msg) elif any(param.is_complex() for param in problem.parameters()): reductions = [EvalParams()] + reductions # Conclude with matrix stuffing; choose one of the following paths: # (1) QpMatrixStuffing --> [a QpSolver], # (2) ConeMatrixStuffing --> [a ConicSolver] if _solve_as_qp(problem, candidates): # Canonicalize as a QP solver = sorted(candidates['qp_solvers'], key=lambda s: slv_def.QP_SOLVERS.index(s))[0] solver_instance = slv_def.SOLVER_MAP_QP[solver] reductions += [QpMatrixStuffing(), solver_instance] return SolvingChain(reductions=reductions) # Canonicalize as a cone program 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) # 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 NONPOS_ATOMS for atom in atoms) or any( type(c) in [Inequality, NonPos, NonNeg] for c in problem.constraints)): cones.append(NonNeg) if (any(type(c) in [Equality, Zero] for c in problem.constraints)): cones.append(Zero) 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(candidates['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 += [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." % (candidates['conic_solvers'], ", ".join( [cone.__name__ for cone in cones])))
def stuff(mat): ConeMatrixStuffing().apply(mat)