def _dual_apply(c, A, b, K): f, G, h, Kd = dualize_problem(c, A, b, K) # max{ f @ y : G @ y == h, y in Kd} type_selectors = build_cone_type_selectors(Kd) G_ineq = G[:, type_selectors['+']] f_ineq = f[type_selectors['+']] G_free = G[:, type_selectors['fr']] f_free = f[type_selectors['fr']] G_dexp = G[:, type_selectors['de']] f_dexp = f[type_selectors['de']] G_soc = G[:, type_selectors['S']] f_soc = f[type_selectors['S']] f = np.concatenate((f_ineq, f_soc, f_dexp, f_free)) G = sp.hstack((G_ineq, G_soc, G_dexp, G_free), format='csc') cones = { '+': np.count_nonzero(type_selectors['+']), 'S': [Ki.len for Ki in Kd if Ki.type == 'S'], 'de': len([Ki for Ki in Kd if Ki.type == 'de']), 'fr': np.count_nonzero(type_selectors['fr']) } inv_data = { 'A': A, 'b': b, 'K': K, 'c': c, 'type_selectors': type_selectors, 'dual': True, 'n': A.shape[1] } data = {'f': f, 'G': G, 'h': h, 'cone_dims': cones} return data, inv_data
def apply(c, A, b, K, params): """ :return: G, h, cones, A_ecos, b_ecos --- where we expect a function call: sol = ecos.solve(c, G, h, cones, A_ecos, b_ecos) """ for co in K: if co.type not in {'e', 'S', '+', '0'}: # pragma: no cover msg = """ ECOS only supports cones with labels in the set {"e", "S", "+", "0"}. The provided data includes an invalid cone labeled %s. """ % co.type raise RuntimeError(msg) type_selectors = build_cone_type_selectors(K) # find indices of A corresponding to equality constraints A_ecos = A[type_selectors['0'], :] b_ecos = -b[type_selectors['0']] # move to RHS # Build "G, h". G_nonneg = -A[type_selectors['+'], :] h_nonneg = b[type_selectors['+']] G_soc = -A[type_selectors['S'], :] h_soc = b[type_selectors['S']] G_exp = -A[type_selectors['e'], :] h_exp = b[type_selectors['e']] G = sp.vstack([G_nonneg, G_soc, G_exp], format='csc') h = np.hstack((h_nonneg, h_soc, h_exp)) # create cone dims dict for ECOS cones = { 'l': int(np.sum(type_selectors['+'])), 'e': int(np.sum(type_selectors['e']) / 3), 'q': util.contiguous_selector_lengths(type_selectors['S']) } # ^ The block above probably has a bug. What happens when # two SOC constraints appear back-to-back? data = { 'G': G, 'h': h, 'cones': cones, 'A': A_ecos, 'b': b_ecos, 'c': c } inv_data = dict() return data, inv_data
def _primal_apply(c, A, b, K): inv_data = {'n': A.shape[1]} A, b, K, sep_K = separate_cone_constraints(A, b, K, dont_sep={'0', '+'}) c = np.hstack([c, np.zeros(shape=(A.shape[1] - len(c)))]) type_selectors = build_cone_type_selectors(K) # Below: inequality constraints that the "user" intended to give to MOSEK. A_ineq = A[type_selectors['+'], :] b_ineq = b[type_selectors['+']] # Below: equality constraints that the "user" intended to give to MOSEK A_z = A[type_selectors['0'], :] b_z = b[type_selectors['0']] # Finally: the matrix "A" and vector "u_c" that appear in the MOSEK documentation as the standard form for # an SDP that includes vectorized variables. We use "b" instead of "u_c". It's value in the MOSEK Task will # later be specified with MOSEK's "putconboundlist" function. A = -sp.vstack([A_ineq, A_z], format='csc') b = np.hstack([b_ineq, b_z]) K = [Cone('+', A_ineq.shape[0]), Cone('0', A_z.shape[0])] # Return values data = {'A': A, 'b': b, 'K': K, 'sep_K': sep_K, 'c': c} return data, inv_data
def solve_via_data(data, params): import cvxpy as cp # linear program solving with cvxpy c = data['c'] b = data['b'] A = data['A'] K = data['K'] m, n = A.shape x = cp.Variable(n) for co in K: if co.type not in {'e', 'S', '+', '0', 'pow'}: # pragma: no cover msg = """ The CVXPY interface only supports cones with labels in the set {"e", "S", "+", "0", "pow"}. The provided data includes an invalid cone labeled %s. """ % co.type raise RuntimeError(msg) type_selectors = build_cone_type_selectors(K) constraints = [] cone_types = type_selectors.keys() if '0' in cone_types: tss = type_selectors['0'] constraints.append(A[tss, :] @ x + b[tss] == 0) if 'e' in cone_types: rows = np.where(type_selectors['e'])[0][::3] expr1 = A[rows, :] @ x + b[rows] rows += 1 expr2 = A[rows, :] @ x + b[rows] rows += 1 expr3 = A[rows, :] @ x + b[rows] constraints.append(cp.constraints.ExpCone(expr1, expr3, expr2)) if '+' in cone_types: tss = type_selectors['+'] constraints.append(A[tss, :] @ x + b[tss] >= 0) if 'S' in cone_types or 'pow' in cone_types: idx = 0 for co in K: if co.type == 'S': # first component is epigraph variable upper = A[idx, :] @ x + b[idx] start = idx + 1 lower = A[start:(idx + co.len), :] @ x + b[start:(idx + co.len)] # upper >= norm(lower, 2) constraints.append(cp.constraints.SOC(upper, lower)) elif co.type == 'pow': # final component is hypograph variable stop = idx + (co.len - 1) upper = A[idx:stop, :] @ x + b[idx:stop] lower = A[stop, :] @ x + b[stop] # inclusive weights = co.annotations['weights'] # np.prod(np.power(upper, weights)) >= abs(lower); upper >= 0. constraints.append( cp.constraints.PowConeND(upper, lower, weights)) idx += co.len prob = cp.Problem(cp.Minimize(c @ x), constraints) d = params.copy() d.pop('cache_apply_data') d.pop('cache_raw_output') prob.solve(**d) return x, prob