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 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 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)
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
import numpy as np from cvxpy.reductions.dcp2cone.dcp2cone import Dcp2Cone n = 5 x = cvx.Variable(n) y = cvx.Variable() A = r.rand(n, n) b = r.rand(n, 1) l = np.random.randn(5, 4) c = [cvx.abs(A * x + b) <= 2, cvx.abs(y) + x[0] <= 1, cvx.log1p(x) >= 5] c.append(cvx.log_sum_exp(l, axis=0) <= 10) X = cvx.Variable((5, 5)) c.append(cvx.log_det(X) >= 10) cvx.Minimize(x[0]) prob = cvx.Problem(cvx.Minimize(x[0] + x[1] + y), c) d2c = Dcp2Cone() d2c.accepts(prob) new_prob = d2c.apply(prob) print(prob) print('\n\n') print(new_prob) prob.solve() new_prob.solve() print(prob.value) print(new_prob.value)