def _prepare_data_and_inv_data(self, problem): data = {} inv_data = {self.VAR_ID: problem.x.id} # Format constraints # # SCS requires constraints to be specified in the following order: # 1. zero cone # 2. non-negative orthant # 3. soc # 4. psd # 5. exponential constr_map = group_constraints(problem.constraints) data[ConicSolver.DIMS] = ConeDims(constr_map) inv_data[ConicSolver.DIMS] = data[ConicSolver.DIMS] zero_constr = constr_map[Zero] neq_constr = (constr_map[NonPos] + constr_map[SOC] + constr_map[PSD] + constr_map[ExpCone]) inv_data[SCS.EQ_CONSTR] = zero_constr inv_data[SCS.NEQ_CONSTR] = neq_constr if not problem.formatted: problem = self.format_constraints(problem, self.EXP_CONE_ORDER) data[s.PARAM_PROB] = problem return problem, data, inv_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 __init__(self, c, x, A, variables, var_id_to_col, constraints, parameters, param_id_to_col, formatted: bool = False) -> None: # The problem data tensors; c is for the constraint, and A for # the problem data matrix self.c = c self.A = A # The variable self.x = x self.reduced_A = None self.problem_data_tensor = None self._A_mapping_nonzero = None self.constraints = constraints self.constr_size = sum([c.size for c in constraints]) self.constr_map = group_constraints(constraints) self.cone_dims = ConeDims(self.constr_map) self.parameters = parameters self.param_id_to_col = param_id_to_col self.id_to_param = {p.id: p for p in self.parameters} self.param_id_to_size = {p.id: p.size for p in self.parameters} self.total_param_size = sum([p.size for p in self.parameters]) # TODO technically part of inverse data. self.variables = variables self.var_id_to_col = var_id_to_col self.id_to_var = {v.id: v for v in self.variables} # whether this param cone prog has been formatted for a solver self.formatted = formatted
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.x.id} constr_map = group_constraints(problem.constraints) data[ConicSolver.DIMS] = ConeDims(constr_map) inv_data[ConicSolver.DIMS] = data[ConicSolver.DIMS] len_eq = sum([c.size for c in constr_map[Zero]]) inv_data[self.EQ_CONSTR] = constr_map[Zero] neq_constr = constr_map[NonPos] + constr_map[SOC] + constr_map[PSD] inv_data[self.NEQ_CONSTR] = neq_constr if not problem.formatted: problem = self.format_constraints(problem, ECOS.EXP_CONE_ORDER) data[s.PARAM_PROB] = problem c, d, A, b = problem.apply_parameters() data[s.C] = c inv_data[s.OFFSET] = d data[s.A] = -A[:len_eq] if data[s.A].shape[0] == 0: data[s.A] = None data[s.B] = b[:len_eq].flatten() if data[s.B].shape[0] == 0: data[s.B] = None data[s.G] = -A[len_eq:] data[s.H] = b[len_eq:].flatten() return data, inv_data
def _prepare_data_and_inv_data(self, problem): data = {} inv_data = {self.VAR_ID: problem.x.id} constr_map = group_constraints(problem.constraints) data[QpSolver.DIMS] = ConeDims(constr_map) inv_data[QpSolver.DIMS] = data[QpSolver.DIMS] # Add information about integer variables inv_data[QpSolver.IS_MIP] = problem.is_mixed_integer() data[s.PARAM_PROB] = problem return problem, data, inv_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 __init__(self, c, x, A, variables, var_id_to_col, constraints, parameters, param_id_to_col, formatted=False): # The problem data tensors; c is for the constraint, and A for # the problem data matrix self.c = c self.A = A # The variable self.x = x # Form a reduced representation of A, for faster application of # parameters. if np.prod(A.shape) != 0: reduced_A, indices, indptr, shape = ( canonInterface.reduce_problem_data_tensor(A, self.x.size)) self.reduced_A = reduced_A self.problem_data_index = (indices, indptr, shape) else: self.reduced_A = A self.problem_data_index = None self._A_mapping_nonzero = None self.constraints = constraints self.constr_size = sum([c.size for c in constraints]) self.constr_map = group_constraints(constraints) self.cone_dims = ConeDims(self.constr_map) self.parameters = parameters self.param_id_to_col = param_id_to_col self.id_to_param = {p.id: p for p in self.parameters} self.param_id_to_size = {p.id: p.size for p in self.parameters} self.total_param_size = sum([p.size for p in self.parameters]) # TODO technically part of inverse data. self.variables = variables self.var_id_to_col = var_id_to_col self.id_to_var = {v.id: v for v in self.variables} # whether this param cone prog has been formatted for a solver self.formatted = formatted
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.x.id} # Format constraints # # ECOS requires constraints to be specified in the following order: # 1. zero cone # 2. non-negative orthant # 3. soc # 4. exponential constr_map = group_constraints(problem.constraints) data[ConicSolver.DIMS] = ConeDims(constr_map) inv_data[ConicSolver.DIMS] = data[ConicSolver.DIMS] len_eq = sum([c.size for c in constr_map[Zero]]) inv_data[self.EQ_CONSTR] = constr_map[Zero] neq_constr = constr_map[NonPos] + constr_map[SOC] + constr_map[ExpCone] inv_data[self.NEQ_CONSTR] = neq_constr if not problem.formatted: problem = self.format_constraints(problem, self.EXP_CONE_ORDER) data[s.PARAM_PROB] = problem c, d, A, b = problem.apply_parameters() data[s.C] = c inv_data[s.OFFSET] = d data[s.A] = -A[:len_eq] if data[s.A].shape[0] == 0: data[s.A] = None data[s.B] = b[:len_eq].flatten() if data[s.B].shape[0] == 0: data[s.B] = None data[s.G] = -A[len_eq:] if 0 in data[s.G].shape: data[s.G] = None data[s.H] = b[len_eq:].flatten() if 0 in data[s.H].shape: data[s.H] = None return data, inv_data
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.x.id} # Format constraints # # SCS requires constraints to be specified in the following order: # 1. zero cone # 2. non-negative orthant # 3. soc # 4. psd # 5. exponential constr_map = group_constraints(problem.constraints) data[ConicSolver.DIMS] = ConeDims(constr_map) inv_data[ConicSolver.DIMS] = data[ConicSolver.DIMS] zero_constr = constr_map[Zero] neq_constr = (constr_map[NonPos] + constr_map[SOC] + constr_map[PSD] + constr_map[ExpCone]) inv_data[SCS.EQ_CONSTR] = zero_constr inv_data[SCS.NEQ_CONSTR] = neq_constr if not problem.formatted: problem = self.format_constraints(problem, self.EXP_CONE_ORDER) data[s.PARAM_PROB] = problem # Apply parameter values. # Obtain A, b such that Ax + s = b, s \in cones. # # Note that scs mandates that the cones MUST be ordered with # zero cones first, then non-nonnegative orthant, then SOC, # then PSD, then exponential. c, d, A, b = problem.apply_parameters() data[s.C] = c inv_data[s.OFFSET] = d data[s.A] = -A data[s.B] = b return data, inv_data
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.x.id} constr_map = group_constraints(problem.constraints) data[ConicSolver.DIMS] = ConeDims(constr_map) inv_data[ConicSolver.DIMS] = data[ConicSolver.DIMS] len_eq = sum([c.size for c in constr_map[Zero]]) inv_data[self.EQ_CONSTR] = constr_map[Zero] neq_constr = constr_map[NonPos] + constr_map[SOC] + constr_map[PSD] inv_data[self.NEQ_CONSTR] = neq_constr if not problem.formatted: problem = self.format_constraints(problem, ECOS.EXP_CONE_ORDER) data[s.PARAM_PROB] = problem c, d, A, b = problem.apply_parameters() data[s.C] = c inv_data[s.OFFSET] = d data[s.A] = -A[:len_eq] if data[s.A].shape[0] == 0: data[s.A] = None data[s.B] = b[:len_eq].flatten() if data[s.B].shape[0] == 0: data[s.B] = None if len_eq > A.shape[1]: # Then the given optimization problem has no conic constraints. # This is certainly a degenerate case, but we'll handle it downstream. data[s.G] = sp.csc_matrix((1, A.shape[1])) data[s.H] = np.array([0]) else: data[s.G] = -A[len_eq:] data[s.H] = b[len_eq:].flatten() return data, inv_data
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 = dict() var = problem.x inv_data = { self.VAR_ID: var.id, 'suc_slacks': [], 'y_slacks': [], 'snx_slacks': [], 'psd_dims': [] } # Get integrality constraint information data[s.BOOL_IDX] = [int(t[0]) for t in var.boolean_idx] data[s.INT_IDX] = [int(t[0]) for t in var.integer_idx] inv_data['integer_variables'] = len(data[s.BOOL_IDX]) + len( data[s.INT_IDX]) > 0 constr_map = group_constraints(problem.constraints) data[s.DIMS] = ConeDims(constr_map) if not problem.formatted: problem = self.format_constraints(problem, MOSEK.EXP_CONE_ORDER) data[s.PARAM_PROB] = problem inv_data['constraints'] = problem.constraints # A is ordered as [Zero, NonPos, SOC, PSD, EXP] c, d, A, b = problem.apply_parameters() A = -A data[s.C] = c.ravel() inv_data['n0'] = len(data[s.C]) data[s.OBJ_OFFSET] = float(d) inv_data[s.OBJ_OFFSET] = float(d) Gs = [] hs = [] # Linear inequalities num_linear_equalities = len(constr_map[Zero]) num_linear_inequalities = len(constr_map[NonPos]) leq_dim = data[s.DIMS][s.LEQ_DIM] eq_dim = data[s.DIMS][s.EQ_DIM] if num_linear_inequalities > 0: # G, h : G * z <= h offset = num_linear_equalities for c in problem.constraints[offset:offset + num_linear_inequalities]: assert (isinstance(c, NonPos)) inv_data['suc_slacks'].append((c.id, c.size)) row_offset = eq_dim Gs.append(A[row_offset:row_offset + leq_dim]) hs.append(b[row_offset:row_offset + leq_dim]) # Linear equations if num_linear_equalities > 0: for c in problem.constraints[:num_linear_equalities]: assert (isinstance(c, Zero)) inv_data['y_slacks'].append((c.id, c.size)) Gs.append(A[:eq_dim]) hs.append(b[:eq_dim]) # Second order cone num_soc = len(constr_map[SOC]) soc_dim = sum(data[s.DIMS][s.SOC_DIM]) if num_soc > 0: offset = num_linear_inequalities + num_linear_equalities for c in problem.constraints[offset:offset + num_soc]: assert (isinstance(c, SOC)) inv_data['snx_slacks'].append((c.id, c.size)) row_offset = leq_dim + eq_dim Gs.append(A[row_offset:row_offset + soc_dim]) hs.append(b[row_offset:row_offset + soc_dim]) # Exponential cone num_exp = len(constr_map[ExpCone]) if num_exp > 0: # G * z <=_{EXP} h. for c in problem.constraints[-num_exp:]: assert (isinstance(c, ExpCone)) inv_data['snx_slacks'].append((c.id, c.num_cones())) Gs.append(A[-num_exp:]) hs.append(b[-num_exp:]) # PSD constraints num_psd = len(constr_map[PSD]) psd_dim = sum([dim**2 for dim in data[s.DIMS][s.PSD_DIM]]) if num_psd > 0: offset = num_linear_inequalities + num_linear_equalities + num_soc for c in problem.constraints[offset:offset + num_psd]: assert (isinstance(c, PSD)) inv_data['psd_dims'].append((c.id, c.expr.shape[0])) row_offset = leq_dim + eq_dim + soc_dim Gs.append(A[row_offset:row_offset + psd_dim]) hs.append(b[row_offset:row_offset + psd_dim]) if Gs: data[s.G] = sp.sparse.vstack(tuple(Gs)) else: data[s.G] = sp.sparse.csc_matrix((0, 0)) if hs: data[s.H] = np.hstack(tuple(hs)) else: data[s.H] = np.array([]) inv_data['is_LP'] = (len(constr_map[PSD]) + len(constr_map[ExpCone]) + len(constr_map[SOC])) == 0 return data, inv_data
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 = dict() inv_data = dict() inv_data[self.VAR_ID] = problem.x.id constr_map = group_constraints(problem.constraints) data[s.DIMS] = ConeDims(constr_map) if not problem.formatted: problem = self.format_constraints(problem, exp_cone_order=None) c, d, A, b = problem.apply_parameters() A = -A data[s.C] = c.ravel() data[s.OBJ_OFFSET] = float(d) inv_data[s.OBJ_OFFSET] = float(d) inv_data['lin_dim'] = [] inv_data['soc_dim'] = [] Gs = list() hs = list() # Linear inequalities num_linear_eq = len(constr_map[Zero]) num_linear_leq = len(constr_map[NonPos]) leq_dim = data[s.DIMS][s.LEQ_DIM] eq_dim = data[s.DIMS][s.EQ_DIM] if num_linear_leq > 0: offset = num_linear_eq for con in problem.constraints[offset:offset + num_linear_leq]: inv_data['lin_dim'].append((con.id, con.size)) row_offset = eq_dim Gs.append(A[row_offset:row_offset + leq_dim]) hs.append(b[row_offset:row_offset + leq_dim]) # Linear equations if num_linear_eq > 0: for con in problem.constraints[:num_linear_eq]: inv_data['lin_dim'].append((con.id, con.size)) Gs.append(A[:eq_dim]) hs.append(b[:eq_dim]) # Second order cones num_soc = len(constr_map[SOC]) soc_dim = sum(data[s.DIMS][s.SOC_DIM]) if num_soc > 0: offset = num_linear_eq + num_linear_leq for con in problem.constraints[offset:offset + num_soc]: inv_data['soc_dim'].append((con.id, con.size)) row_offset = leq_dim + eq_dim Gs.append(A[row_offset:row_offset + soc_dim]) hs.append(b[row_offset:row_offset + soc_dim]) data['nvar'] = len(c) + sum(data[s.DIMS][s.SOC_DIM]) inv_data['nr'] = len(c) if Gs: data[s.G] = sp.sparse.vstack(tuple(Gs)) else: data[s.G] = sp.sparse.csc_matrix((0, 0)) if hs: data[s.H] = np.hstack(tuple(hs)) else: data[s.H] = np.array([]) return (data, inv_data)