def apply(self, problem): inverse_data = InverseData(problem) real2imag = { var.id: lu.get_id() for var in problem.variables() if var.is_complex() } constr_dict = { cons.id: lu.get_id() for cons in problem.constraints if cons.is_complex() } real2imag.update(constr_dict) inverse_data.real2imag = real2imag leaf_map = {} real_obj, imag_obj = self.canonicalize_tree(problem.objective, inverse_data.real2imag, leaf_map) assert imag_obj is None constrs = [] for constraint in problem.constraints: # real2imag maps variable id to a potential new variable # created for the imaginary part. real_constrs, imag_constrs = self.canonicalize_tree( constraint, inverse_data.real2imag, leaf_map) if real_constrs is not None: constrs.extend(real_constrs) if imag_constrs is not None: constrs.extend(imag_constrs) new_problem = problems.problem.Problem(real_obj, constrs) return new_problem, inverse_data
def apply(self, problem): """See docstring for MatrixStuffing.apply""" inverse_data = InverseData(problem) # Form the constraints extractor = CoeffExtractor(inverse_data) params_to_P, params_to_q, flattened_variable = self.stuffed_objective( problem, extractor) # Lower equality and inequality to Zero and NonPos. cons = [] for con in problem.constraints: if isinstance(con, Equality): con = lower_equality(con) elif isinstance(con, Inequality): con = lower_ineq_to_nonpos(con) cons.append(con) # Reorder constraints to Zero, NonPos. constr_map = group_constraints(cons) ordered_cons = constr_map[Zero] + constr_map[NonPos] inverse_data.cons_id_map = {con.id: con.id for con in ordered_cons} inverse_data.constraints = ordered_cons # Batch expressions together, then split apart. expr_list = [arg for c in ordered_cons for arg in c.args] params_to_Ab = extractor.affine(expr_list) inverse_data.minimize = type(problem.objective) == Minimize new_prob = ParamQuadProg(params_to_P, params_to_q, flattened_variable, params_to_Ab, problem.variables(), inverse_data.var_offsets, ordered_cons, problem.parameters(), inverse_data.param_id_map) return new_prob, inverse_data
def apply(self, problem): inverse_data = InverseData(problem) # Form the constraints extractor = CoeffExtractor(inverse_data) params_to_objective, flattened_variable = self.stuffed_objective( problem, extractor) # Lower equality and inequality to Zero and NonNeg. cons = [] for con in problem.constraints: if isinstance(con, Equality): con = lower_equality(con) elif isinstance(con, Inequality): con = lower_ineq_to_nonneg(con) elif isinstance(con, NonPos): con = nonpos2nonneg(con) elif isinstance(con, SOC) and con.axis == 1: con = SOC(con.args[0], con.args[1].T, axis=0, constr_id=con.constr_id) elif isinstance(con, PowCone3D) and con.args[0].ndim > 1: x, y, z = con.args alpha = con.alpha con = PowCone3D(x.flatten(), y.flatten(), z.flatten(), alpha.flatten(), constr_id=con.constr_id) elif isinstance(con, ExpCone) and con.args[0].ndim > 1: x, y, z = con.args con = ExpCone(x.flatten(), y.flatten(), z.flatten(), constr_id=con.constr_id) cons.append(con) # Reorder constraints to Zero, NonNeg, SOC, PSD, EXP, PowCone3D constr_map = group_constraints(cons) ordered_cons = constr_map[Zero] + constr_map[NonNeg] + \ constr_map[SOC] + constr_map[PSD] + constr_map[ExpCone] + constr_map[PowCone3D] inverse_data.cons_id_map = {con.id: con.id for con in ordered_cons} inverse_data.constraints = ordered_cons # Batch expressions together, then split apart. expr_list = [arg for c in ordered_cons for arg in c.args] params_to_problem_data = extractor.affine(expr_list) inverse_data.minimize = type(problem.objective) == Minimize new_prob = ParamConeProg(params_to_objective, flattened_variable, params_to_problem_data, problem.variables(), inverse_data.var_offsets, ordered_cons, problem.parameters(), inverse_data.param_id_map) return new_prob, inverse_data
def apply(self, problem): inverse_data = InverseData(problem) leaf_map = {} real_obj, imag_obj = self.canonicalize_tree(problem.objective, inverse_data.real2imag, leaf_map) assert imag_obj is None constrs = [] for constraint in problem.constraints: if type(constraint) == Equality: constraint = utilities.lower_equality(constraint) elif type(constraint) == Inequality: constraint = utilities.lower_inequality(constraint) # real2imag maps variable id to a potential new variable # created for the imaginary part. real_constrs, imag_constrs = self.canonicalize_tree( constraint, inverse_data.real2imag, leaf_map) if real_constrs is not None: constrs.extend(real_constrs) if imag_constrs is not None: constrs.extend(imag_constrs) new_problem = problems.problem.Problem(real_obj, constrs) return new_problem, inverse_data
def apply(self, problem): inverse_data = InverseData(problem) new_obj, new_var = self.stuffed_objective(problem, inverse_data) # Form the constraints extractor = CoeffExtractor(inverse_data) new_cons = [] for con in problem.constraints: arg_list = [] for arg in con.args: A, b = extractor.get_coeffs(arg) arg_list.append(reshape(A * new_var + b, arg.shape)) new_cons.append(con.copy(arg_list)) inverse_data.cons_id_map[con.id] = new_cons[-1].id # Map of old constraint id to new constraint id. inverse_data.minimize = type(problem.objective) == Minimize new_prob = problems.problem.Problem(Minimize(new_obj), new_cons) return new_prob, inverse_data
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
def apply(self, problem): """See docstring for MatrixStuffing.apply""" inverse_data = InverseData(problem) # Form the constraints extractor = CoeffExtractor(inverse_data) new_obj, new_var, r = self.stuffed_objective(problem, extractor) inverse_data.r = r # Lower equality and inequality to Zero and NonPos. cons = [] for con in problem.constraints: if isinstance(con, Equality): con = lower_equality(con) elif isinstance(con, Inequality): con = lower_inequality(con) cons.append(con) # Batch expressions together, then split apart. expr_list = [arg for c in cons for arg in c.args] problem_data_tensor = extractor.affine(expr_list) Afull, bfull = canon.get_matrix_and_offset_from_unparameterized_tensor( problem_data_tensor, new_var.size) if 0 not in Afull.shape and 0 not in bfull.shape: Afull = cvxtypes.constant()(Afull) bfull = cvxtypes.constant()(np.atleast_1d(bfull)) new_cons = [] offset = 0 for orig_con, con in zip(problem.constraints, cons): arg_list = [] for arg in con.args: A = Afull[offset:offset + arg.size, :] b = bfull[offset:offset + arg.size] arg_list.append(reshape(A @ new_var + b, arg.shape)) offset += arg.size new_constraint = con.copy(arg_list) new_cons.append(new_constraint) inverse_data.constraints = new_cons inverse_data.minimize = type(problem.objective) == Minimize new_prob = problems.problem.Problem(Minimize(new_obj), new_cons) return new_prob, inverse_data
def apply(self, problem): inverse_data = InverseData(problem) # Form the constraints extractor = CoeffExtractor(inverse_data) new_obj, new_var, r = self.stuffed_objective(problem, extractor) inverse_data.r = r # Lower equality and inequality to Zero and NonPos. cons = [] for con in problem.constraints: if isinstance(con, Equality): con = lower_equality(con) elif isinstance(con, Inequality): con = lower_inequality(con) elif isinstance(con, SOC) and con.axis == 1: con = SOC(con.args[0], con.args[1].T, axis=0, constr_id=con.constr_id) cons.append(con) # Batch expressions together, then split apart. expr_list = [arg for con in cons for arg in con.args] Afull, bfull = extractor.affine(expr_list) new_cons = [] offset = 0 for con in cons: arg_list = [] for arg in con.args: A = Afull[offset:offset + arg.size, :] b = bfull[offset:offset + arg.size] arg_list.append(reshape(A * new_var + b, arg.shape)) offset += arg.size new_cons.append(con.copy(arg_list)) inverse_data.cons_id_map[con.id] = new_cons[-1].id # Map of old constraint id to new constraint id. inverse_data.minimize = type(problem.objective) == Minimize new_prob = problems.problem.Problem(Minimize(new_obj), new_cons) return new_prob, inverse_data
def apply(self, problem): inverse_data = InverseData(problem) canon_objective, canon_constraints = self.canonicalize_tree( problem.objective) for constraint in problem.constraints: # canon_constr is the constraint rexpressed in terms of # its canonicalized arguments, and aux_constr are the constraints # generated while canonicalizing the arguments of the original # constraint canon_constr, aux_constr = self.canonicalize_tree(constraint) canon_constraints += aux_constr + [canon_constr] inverse_data.cons_id_map.update({constraint.id: canon_constr.id}) new_problem = problems.problem.Problem(canon_objective, canon_constraints) return new_problem, inverse_data
def stuffed_objective(self, problem, inverse_data): # We need to copy the problem because we are changing atoms in the # expression tree problem_copy = problems.problem.Problem( Minimize(problem.objective.expr.tree_copy()), [con.tree_copy() for con in problem.constraints]) inverse_data_of_copy = InverseData(problem_copy) extractor = CoeffExtractor(inverse_data_of_copy) # extract to x.T * P * x + q.T * x, store r P, q, r = extractor.quad_form(problem_copy.objective.expr) # concatenate all variables in one vector boolean, integer = extract_mip_idx(problem.variables()) x = Variable(inverse_data.x_length, boolean=boolean, integer=integer) new_obj = QuadForm(x, P) + q.T * x inverse_data.r = r return new_obj, x
def apply(self, problem): inverse_data = InverseData(problem) leaf_map = {} real_obj, imag_obj = self.canonicalize_tree( problem.objective, inverse_data.real2imag, leaf_map) assert imag_obj is None constrs = [] for constraint in problem.constraints: real_constr, imag_constr = self.canonicalize_tree( constraint, inverse_data.real2imag, leaf_map) if real_constr is not None: constrs.append(real_constr) if imag_constr is not None: constrs.append(imag_constr) new_problem = problems.problem.Problem(real_obj, constrs) return new_problem, inverse_data
def apply(self, problem): """Returns a stuffed problem. The returned problem is a minimization problem in which every constraint in the problem has affine arguments that are expressed in the form A @ x + b. Parameters ---------- problem: The problem to stuff; the arguments of every constraint must be affine constraints: A list of constraints, whose arguments are affine Returns ------- Problem The stuffed problem InverseData Data for solution retrieval """ inverse_data = InverseData(problem) # Form the constraints extractor = CoeffExtractor(inverse_data) new_obj, new_var, r = self.stuffed_objective(problem, extractor) inverse_data.r = r # Lower equality and inequality to Zero and NonPos. cons = [] for con in problem.constraints: if isinstance(con, Equality): con = lower_equality(con) elif isinstance(con, Inequality): con = lower_inequality(con) elif isinstance(con, SOC) and con.axis == 1: con = SOC(con.args[0], con.args[1].T, axis=0, constr_id=con.constr_id) cons.append(con) # Batch expressions together, then split apart. expr_list = [arg for c in cons for arg in c.args] Afull, bfull = extractor.affine(expr_list) if 0 not in Afull.shape and 0 not in bfull.shape: Afull = cvxtypes.constant()(Afull) bfull = cvxtypes.constant()(bfull) new_cons = [] offset = 0 for con in cons: arg_list = [] for arg in con.args: A = Afull[offset:offset+arg.size, :] b = bfull[offset:offset+arg.size] arg_list.append(reshape(A*new_var + b, arg.shape)) offset += arg.size new_cons.append(con.copy(arg_list)) # Map old constraint id to new constraint id. inverse_data.cons_id_map[con.id] = new_cons[-1].id inverse_data.minimize = type(problem.objective) == Minimize new_prob = problems.problem.Problem(Minimize(new_obj), new_cons) return new_prob, inverse_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