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 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 apply(self, problem): """Returns a new problem and data for inverting the new solution. Returns ------- tuple (dict of arguments needed for the solver, inverse data) """ data = {} inv_data = {self.VAR_ID: problem.variables()[0].id} data[s.C], data[s.OFFSET] = ConicSolver.get_coeff_offset( problem.objective.args[0]) data[s.C] = data[s.C].ravel() inv_data[s.OFFSET] = data[s.OFFSET][0] constr_map = group_constraints(problem.constraints) data[ConicSolver.DIMS] = ConeDims(constr_map) inv_data[self.EQ_CONSTR] = constr_map[Zero] data[s.A], data[s.B] = self.group_coeff_offset( problem, constr_map[Zero], ECOS.EXP_CONE_ORDER) # Order and group nonlinear constraints. neq_constr = constr_map[NonPos] + constr_map[SOC] + constr_map[PSD] inv_data[self.NEQ_CONSTR] = neq_constr data[s.G], data[s.H] = self.group_coeff_offset( problem, neq_constr, ECOS.EXP_CONE_ORDER) return data, inv_data
def apply(self, problem): """ Construct QP problem data stored in a dictionary. The QP has the following form minimize 1/2 x' P x + q' x subject to A x = b F x <= g """ inverse_data = InverseData(problem) obj = problem.objective # quadratic part of objective is x.T * P * x but solvers expect # 0.5*x.T * P * x. P = 2 * obj.expr.args[0].args[1].value q = obj.expr.args[1].args[0].value.flatten() # Get number of variables n = problem.size_metrics.num_scalar_variables # TODO(akshayka): This dependence on ConicSolver is hacky; something # should change here. eq_cons = [c for c in problem.constraints if type(c) == Zero] if eq_cons: eq_coeffs = list( zip(*[ ConicSolver.get_coeff_offset(con.expr) for con in eq_cons ])) A = sp.vstack(eq_coeffs[0]) b = -np.concatenate(eq_coeffs[1]) else: A, b = sp.csr_matrix((0, n)), -np.array([]) ineq_cons = [c for c in problem.constraints if type(c) == NonPos] if ineq_cons: ineq_coeffs = list( zip(*[ ConicSolver.get_coeff_offset(con.expr) for con in ineq_cons ])) F = sp.vstack(ineq_coeffs[0]) g = -np.concatenate(ineq_coeffs[1]) else: F, g = sp.csr_matrix((0, n)), -np.array([]) # Create dictionary with problem data variables = problem.variables()[0] data = {} data[s.P] = sp.csc_matrix(P) data[s.Q] = q data[s.A] = sp.csc_matrix(A) data[s.B] = b data[s.F] = sp.csc_matrix(F) data[s.G] = g data[s.BOOL_IDX] = [t[0] for t in variables.boolean_idx] data[s.INT_IDX] = [t[0] for t in variables.integer_idx] data['n_var'] = n data['n_eq'] = A.shape[0] data['n_ineq'] = F.shape[0] inverse_data.sorted_constraints = eq_cons + ineq_cons # Add information about integer variables inverse_data.is_mip = \ len(data[s.BOOL_IDX]) > 0 or len(data[s.INT_IDX]) > 0 return data, inverse_data