def graph_implementation(arg_objs, size, data=None): """Reduces the atom to an affine expression and list of constraints. Parameters ---------- arg_objs : list LinExpr for each argument. size : tuple The size of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) """ x = arg_objs[0] w = lu.create_var(size) v = lu.create_var(size) two = lu.create_const(2, (1, 1)) # w**2 + 2*v obj, constraints = square.graph_implementation([w], size) obj = lu.sum_expr([obj, lu.mul_expr(two, v, size)]) # x <= w + v constraints.append(lu.create_leq(x, lu.sum_expr([w, v]))) # v >= 0 constraints.append(lu.create_geq(v)) return (obj, constraints)
def graph_implementation(arg_objs, size, data=None): """Reduces the atom to an affine expression and list of constraints. Parameters ---------- arg_objs : list LinExpr for each argument. size : tuple The size of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) """ # min sum_entries(t) + kq # s.t. x <= t + q # 0 <= t x = arg_objs[0] k = lu.create_const(data[0], (1, 1)) q = lu.create_var((1, 1)) t = lu.create_var(x.size) sum_t, constr = sum_entries.graph_implementation([t], (1, 1)) obj = lu.sum_expr([sum_t, lu.mul_expr(k, q, (1, 1))]) prom_q = lu.promote(q, x.size) constr.append(lu.create_leq(x, lu.sum_expr([t, prom_q]))) constr.append(lu.create_geq(t)) return (obj, constr)
def graph_implementation(arg_objs, size, data=None): """Reduces the atom to an affine expression and list of constraints. Parameters ---------- arg_objs : list LinExpr for each argument. size : tuple The size of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) """ # min sum_entries(t) + kq # s.t. x <= t + q # 0 <= t x = arg_objs[0] k = lu.create_const(data[0], (1, 1)) q = lu.create_var((1, 1)) t = lu.create_var(x.size) sum_t, constr = sum_entries.graph_implementation([t], (1, 1)) obj = lu.sum_expr([sum_t, lu.mul_expr(k, q, (1, 1))]) prom_q = lu.promote(q, x.size) constr.append( lu.create_leq(x, lu.sum_expr([t, prom_q])) ) constr.append( lu.create_geq(t) ) return (obj, constr)
def constraints(self): obj, constraints = super(BoolVar, self).canonicalize() one = lu.create_const(1, (1, 1)) constraints += [lu.create_geq(obj), lu.create_leq(obj, one)] for i in range(self.size[0]): row_sum = lu.sum_expr([self[i, j] for j in range(self.size[0])]) col_sum = lu.sum_expr([self[j, i] for j in range(self.size[0])]) constraints += [lu.create_eq(row_sum, one), lu.create_eq(col_sum, one)] return constraints
def graph_implementation(arg_objs, size, data=None): # min 1-sqrt(2z-z^2) # s.t. x>=0, z<=1, z = x+s, s<=0 x = arg_objs[0] z = lu.create_var(size) s = lu.create_var(size) zeros = lu.create_const(np.mat(np.zeros(size)),size) ones = lu.create_const(np.mat(np.ones(size)),size) z2, constr_square = power.graph_implementation([z],size, (2, (Fraction(1,2), Fraction(1,2)))) two_z = lu.sum_expr([z,z]) sub = lu.sub_expr(two_z, z2) sq, constr_sqrt = power.graph_implementation([sub],size, (Fraction(1,2), (Fraction(1,2), Fraction(1,2)))) obj = lu.sub_expr(ones, sq) constr = [lu.create_eq(z, lu.sum_expr([x,s]))]+[lu.create_leq(zeros,x)]+[lu.create_leq(z, ones)]+[lu.create_leq(s,zeros)]+constr_square+constr_sqrt return (obj, constr)
def graph_implementation(arg_objs, size, data=None): """Reduces the atom to an affine expression and list of constraints. Parameters ---------- arg_objs : list LinExpr for each argument. size : tuple The size of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) """ x = arg_objs[0] y = arg_objs[1] # Known to be a scalar. v = lu.create_var((1, 1)) two = lu.create_const(2, (1, 1)) constraints = [SOC(lu.sum_expr([y, v]), [lu.sub_expr(y, v), lu.mul_expr(two, x, x.size)]), lu.create_geq(y)] return (v, constraints)
def graph_implementation(arg_objs, size, data=None): """Reduces the atom to an affine expression and list of constraints. Parameters ---------- arg_objs : list LinExpr for each argument. size : tuple The size of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) """ # Promote scalars. for idx, arg in enumerate(arg_objs): if arg.size != size: arg_objs[idx] = lu.promote(arg, size) x = arg_objs[0] y = arg_objs[1] v = lu.create_var(x.size) two = lu.create_const(2, (1, 1)) # SOC(x + y, [y - x, 2*v]) constraints = [ SOC_Elemwise(lu.sum_expr([x, y]), [lu.sub_expr(y, x), lu.mul_expr(two, v, v.size)]) ] # 0 <= x, 0 <= y constraints += [lu.create_geq(x), lu.create_geq(y)] return (v, constraints)
def graph_implementation(arg_objs, size, data=None): """Reduces the atom to an affine expression and list of constraints. Parameters ---------- arg_objs : list LinExpr for each argument. size : tuple The size of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) """ x = arg_objs[0] t = lu.create_var(size) # log(1 + exp(x)) <= t <=> exp(-t) + exp(x - t) <= 1 obj0, constr0 = exp.graph_implementation([lu.neg_expr(t)], size) obj1, constr1 = exp.graph_implementation([lu.sub_expr(x, t)], size) lhs = lu.sum_expr([obj0, obj1]) ones = lu.create_const(np.mat(np.ones(size)), size) constr = constr0 + constr1 + [lu.create_leq(lhs, ones)] return (t, constr)
def graph_implementation(arg_objs, size, data=None): """Reduces the atom to an affine expression and list of constraints. Parameters ---------- arg_objs : list LinExpr for each argument. size : tuple The size of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) """ x = arg_objs[0] t = lu.create_var((1, 1)) promoted_t = lu.promote(t, x.size) constraints = [ lu.create_geq(lu.sum_expr([x, promoted_t])), lu.create_leq(x, promoted_t) ] return (t, constraints)
def qol_elemwise(arg_objs, size, data=None): """Reduces the atom to an affine expression and list of constraints. Parameters ---------- arg_objs : list LinExpr for each argument. size : tuple The size of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) """ x = arg_objs[0] y = arg_objs[1] t = lu.create_var(x.size) two = lu.create_const(2, (1, 1)) constraints = [SOC_Elemwise(lu.sum_expr([y, t]), [lu.sub_expr(y, t), lu.mul_expr(two, x, x.size)]), lu.create_geq(y)] return (t, constraints)
def qol_elemwise(arg_objs, size, data=None): """Reduces the atom to an affine expression and list of constraints. Parameters ---------- arg_objs : list LinExpr for each argument. size : tuple The size of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) """ x = arg_objs[0] y = arg_objs[1] t = lu.create_var(x.size) two = lu.create_const(2, (1, 1)) constraints = [ SOC_Elemwise( lu.sum_expr([y, t]), [lu.sub_expr(y, t), lu.mul_expr(two, x, x.size)]), lu.create_geq(y) ] return (t, constraints)
def graph_implementation(arg_objs, size, data=None): """Reduces the atom to an affine expression and list of constraints. Parameters ---------- arg_objs : list LinExpr for each argument. size : tuple The size of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) """ x = arg_objs[0] y = arg_objs[1] t = lu.create_var((1, 1)) constraints = [ExpCone(t, x, y), lu.create_geq(y)] # 0 <= y # -t - x + y obj = lu.sub_expr(y, lu.sum_expr([x, t])) return (obj, constraints)
def graph_implementation(arg_objs, size, data=None): """Reduces the atom to an affine expression and list of constraints. Parameters ---------- arg_objs : list LinExpr for each argument. size : tuple The size of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) """ x = arg_objs[0] y = arg_objs[1] # Known to be a scalar. v = lu.create_var((1, 1)) two = lu.create_const(2, (1, 1)) constraints = [ SOC(lu.sum_expr([y, v]), [lu.sub_expr(y, v), lu.mul_expr(two, x, x.size)]), lu.create_geq(y) ] return (v, constraints)
def constr_func(aff_obj): theta = [lu.create_var((1, 1)) for i in range(len(values))] convex_objs = [] for val, theta_var in zip(values, theta): val_aff = val.canonical_form[0] convex_objs.append( lu.mul_expr(val_aff, theta_var, val_aff.size)) convex_combo = lu.sum_expr(convex_objs) one = lu.create_const(1, (1, 1)) constraints = [ lu.create_eq(aff_obj, convex_combo), lu.create_eq(lu.sum_expr(theta), one) ] for theta_var in theta: constraints.append(lu.create_geq(theta_var)) return constraints
def graph_implementation(arg_objs, size, data=None): """Reduces the atom to an affine expression and list of constraints. Parameters ---------- arg_objs : list LinExpr for each argument. size : tuple The size of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) """ # TODO use log for n != 2. v = lu.create_var((1, 1)) x = arg_objs[0] y = arg_objs[1] two = lu.create_const(2, (1, 1)) # SOC(x + y, [y - x, 2*v]) constraints = [ SOC(lu.sum_expr([x, y]), [lu.sub_expr(y, x), lu.mul_expr(two, v, (1, 1))]) ] # 0 <= x, 0 <= y constraints += [lu.create_geq(x), lu.create_geq(y)] return (v, constraints)
def gm(t, x, y): length = t.size[0] * t.size[1] return SOC_Axis( lu.reshape(lu.sum_expr([x, y]), (length, 1)), lu.vstack([ lu.reshape(lu.sub_expr(x, y), (1, length)), lu.reshape(lu.mul_expr(two, t, t.size), (1, length)) ], (2, length)), 0)
def gm(t, x, y): length = t.size[0]*t.size[1] return SOC_Axis(lu.reshape(lu.sum_expr([x, y]), (length, 1)), lu.vstack([ lu.reshape(lu.sub_expr(x, y), (1, length)), lu.reshape(lu.mul_expr(two, t, t.size), (1, length)) ], (2, length)), 0)
def constr_func(aff_obj): theta = [lu.create_var((1, 1)) for i in xrange(len(values))] convex_objs = [] for val, theta_var in zip(values, theta): val_aff = val.canonical_form[0] convex_objs.append( lu.mul_expr(val_aff, theta_var, val_aff.size) ) convex_combo = lu.sum_expr(convex_objs) one = lu.create_const(1, (1, 1)) constraints = [lu.create_eq(aff_obj, convex_combo), lu.create_eq(lu.sum_expr(theta), one)] for theta_var in theta: constraints.append(lu.create_geq(theta_var)) return constraints
def graph_implementation(arg_objs, size, data=None): """Reduces the atom to an affine expression and list of constraints. Parameters ---------- arg_objs : list LinExpr for each argument. size : tuple The size of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) """ x = arg_objs[0] t = lu.create_var(size) # log(1 + exp(x)) <= t <=> exp(-t) + exp(x - t) <= 1 ''' obj0, constr0 = exp.graph_implementation([lu.neg_expr(t)], size) obj1, constr1 = exp.graph_implementation([lu.sub_expr(x, t)], size) lhs = lu.sum_expr([obj0, obj1]) ones = lu.create_const(np.mat(np.ones(size)), size) constr = constr0 + constr1 + [lu.create_leq(lhs, ones)] ''' s = data[0] if isinstance(s, Parameter): s = lu.create_param(s, (1, 1)) else: # M is constant. s = lu.create_const(s, (1, 1)) #Wrong sign? obj0, constr0 = exp.graph_implementation([lu.neg_expr(t)], size) obj1, constr1 = exp.graph_implementation([lu.sub_expr(s, lu.sum_expr([t, x]))], size) obj2, constr2 = exp.graph_implementation([lu.sub_expr(lu.neg_expr(s), lu.sum_expr([t, x]))], size) obj3, constr3 = exp.graph_implementation([lu.sub_expr(lu.neg_expr(t), lu.mul_expr(2, x, size))], size) lhs = lu.sum_expr([obj0, obj1, obj2, obj3]) ones = lu.create_const(np.mat(np.ones(size)), size) constr = constr0 + constr1 + constr2 + constr3 + [lu.create_leq(lhs, ones)] return (t, constr)
def test_add_expr(self): """Test adding lin expr. """ shape = (5, 4) x = create_var(shape) y = create_var(shape) # Expanding dict. add_expr = sum_expr([x, y]) self.assertEqual(add_expr.shape, shape) assert len(add_expr.args) == 2
def graph_implementation(arg_objs, shape, data=None): """Reduces the atom to an affine expression and list of constraints. minimize n^2 + 2M|s| subject to s + n = x Parameters ---------- arg_objs : list LinExpr for each argument. shape : tuple The shape of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) """ M = data[0] x = arg_objs[0] n = lu.create_var(shape) s = lu.create_var(shape) two = lu.create_const(2, (1, 1)) if isinstance(M, Parameter): M = lu.create_param(M, (1, 1)) else: # M is constant. M = lu.create_const(M.value, (1, 1)) # n**2 + 2*M*|s| n2, constr_sq = power.graph_implementation( [n], shape, (2, (Fraction(1, 2), Fraction(1, 2))) ) abs_s, constr_abs = abs.graph_implementation([s], shape) M_abs_s = lu.mul_expr(M, abs_s) obj = lu.sum_expr([n2, lu.mul_expr(two, M_abs_s)]) # x == s + n constraints = constr_sq + constr_abs constraints.append(lu.create_eq(x, lu.sum_expr([n, s]))) return (obj, constraints)
def graph_implementation(arg_objs, size, data=None): # min 1-sqrt(2z-z^2) # s.t. x>=0, z<=1, z = x+s, s<=0 x = arg_objs[0] z = lu.create_var(size) s = lu.create_var(size) zeros = lu.create_const(np.mat(np.zeros(size)), size) ones = lu.create_const(np.mat(np.ones(size)), size) z2, constr_square = power.graph_implementation( [z], size, (2, (Fraction(1, 2), Fraction(1, 2)))) two_z = lu.sum_expr([z, z]) sub = lu.sub_expr(two_z, z2) sq, constr_sqrt = power.graph_implementation( [sub], size, (Fraction(1, 2), (Fraction(1, 2), Fraction(1, 2)))) obj = lu.sub_expr(ones, sq) constr = [lu.create_eq(z, lu.sum_expr([x, s]))] + [ lu.create_leq(zeros, x) ] + [lu.create_leq(z, ones)] + [lu.create_leq(s, zeros) ] + constr_square + constr_sqrt return (obj, constr)
def graph_implementation(arg_objs,size,data=None): x = arg_objs[0] beta,x0 = data[0],data[1] beta_val,x0_val = beta.value,x0.value if isinstance(beta,Parameter): beta = lu.create_param(beta,(1,1)) else: beta = lu.create_const(beta.value,(1,1)) if isinstance(x0,Parameter): x0 = lu.create_param(x0,(1,1)) else: x0 = lu.create_const(x0.value,(1,1)) xi,psi = lu.create_var(size),lu.create_var(size) one = lu.create_const(1,(1,1)) one_over_beta = lu.create_const(1/beta_val,(1,1)) k = np.exp(-beta_val*x0_val) k = lu.create_const(k,(1,1)) # 1/beta * (1 - exp(-beta*(xi+x0))) xi_plus_x0 = lu.sum_expr([xi,x0]) minus_beta_times_xi_plus_x0 = lu.neg_expr(lu.mul_expr(beta,xi_plus_x0,size)) exp_xi,constr_exp = exp.graph_implementation([minus_beta_times_xi_plus_x0],size) minus_exp_minus_etc = lu.neg_expr(exp_xi) left_branch = lu.mul_expr(one_over_beta, lu.sum_expr([one,minus_exp_minus_etc]),size) # psi*exp(-beta*r0) right_branch = lu.mul_expr(k,psi,size) obj = lu.sum_expr([left_branch,right_branch]) #x-x0 == xi + psi, xi >= 0, psi <= 0 zero = lu.create_const(0,size) constraints = constr_exp prom_x0 = lu.promote(x0, size) constraints.append(lu.create_eq(x,lu.sum_expr([prom_x0,xi,psi]))) constraints.append(lu.create_geq(xi,zero)) constraints.append(lu.create_leq(psi,zero)) return (obj, constraints)
def test_get_vars(self): """Test getting vars from an expression. """ shape = (5, 4) x = create_var(shape) y = create_var(shape) A = create_const(np.ones(shape), shape) # Expanding dict. add_expr = sum_expr([x, y, A]) vars_ = get_expr_vars(add_expr) ref = [(x.data, shape), (y.data, shape)] self.assertCountEqual(vars_, ref)
def graph_implementation(arg_objs, size, data=None): """Reduces the atom to an affine expression and list of constraints. minimize n^2 + 2M|s| subject to s + n = x Parameters ---------- arg_objs : list LinExpr for each argument. size : tuple The size of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) """ M = data x = arg_objs[0] n = lu.create_var(size) s = lu.create_var(size) two = lu.create_const(2, (1, 1)) if isinstance(M, Parameter): M = lu.create_param(M, (1, 1)) else: # M is constant. M = lu.create_const(M.value, (1, 1)) # n**2 + 2*M*|s| n2, constr_sq = square.graph_implementation([n], size) abs_s, constr_abs = abs.graph_implementation([s], size) M_abs_s = lu.mul_expr(M, abs_s, size) obj = lu.sum_expr([n2, lu.mul_expr(two, M_abs_s, size)]) # x == s + n constraints = constr_sq + constr_abs constraints.append(lu.create_eq(x, lu.sum_expr([n, s]))) return (obj, constraints)
def test_leq_constr(self): """Test creating a less than or equal constraint. """ shape = (5, 5) x = create_var(shape) y = create_var(shape) lh_expr = sum_expr([x, y]) value = np.ones(shape) rh_expr = create_const(value, shape) constr = create_leq(lh_expr, rh_expr) self.assertEqual(constr.shape, shape) vars_ = get_expr_vars(constr.expr) ref = [(x.data, shape), (y.data, shape)] self.assertCountEqual(vars_, ref)
def canonicalize(self): """Returns the graph implementation of the object. Marks the top level constraint as the dual_holder, so the dual value will be saved to the EqConstraint. Returns: A tuple of (affine expression, [constraints]). """ obj, constraints = self._expr.canonical_form half = lu.create_const(0.5, (1, 1)) symm = lu.mul_expr(half, lu.sum_expr([obj, lu.transpose(obj)]), obj.size) dual_holder = SDP(symm, enforce_sym=False, constr_id=self.id) return (None, constraints + [dual_holder])
def canonicalize(self): """Returns the graph implementation of the object. Marks the top level constraint as the dual_holder, so the dual value will be saved to the EqConstraint. Returns: A tuple of (affine expression, [constraints]). """ obj, constraints = self._expr.canonical_form half = lu.create_const(0.5, (1,1)) symm = lu.mul_expr(half, lu.sum_expr([obj, lu.transpose(obj)]), obj.size) dual_holder = SDP(symm, enforce_sym=False, constr_id=self.id) return (None, constraints + [dual_holder])
def test_eq_constr(self): """Test creating an equality constraint. """ shape = (5, 5) x = create_var(shape) y = create_var(shape) lh_expr = sum_expr([x, y]) value = np.ones(shape) rh_expr = create_const(value, shape) constr = create_eq(lh_expr, rh_expr) self.assertEqual(constr.shape, shape) vars_ = get_expr_vars(constr.expr) ref = [(x.data, shape), (y.data, shape)] if PY2: self.assertItemsEqual(vars_, ref) else: self.assertCountEqual(vars_, ref)
def format_axis(t, X, axis): """Formats all the row/column cones for the solver. Parameters ---------- t: The scalar part of the second-order constraint. X: A matrix whose rows/columns are each a cone. axis: Slice by column 0 or row 1. Returns ------- list A list of LinLeqConstr that represent all the elementwise cones. """ # Reduce to norms of columns. if axis == 1: X = lu.transpose(X) # Create matrices Tmat, Xmat such that Tmat*t + Xmat*X # gives the format for the elementwise cone constraints. cone_size = 1 + X.shape[0] terms = [] # Make t_mat mat_shape = (cone_size, 1) t_mat = sp.coo_matrix(([1.0], ([0], [0])), mat_shape).tocsc() t_mat = lu.create_const(t_mat, mat_shape, sparse=True) t_vec = t if not t.shape: # t is scalar t_vec = lu.reshape(t, (1, 1)) else: # t is 1D t_vec = lu.reshape(t, (1, t.shape[0])) mul_shape = (cone_size, t_vec.shape[1]) terms += [lu.mul_expr(t_mat, t_vec, mul_shape)] # Make X_mat if len(X.shape) == 1: X = lu.reshape(X, (X.shape[0], 1)) mat_shape = (cone_size, X.shape[0]) val_arr = (cone_size - 1) * [1.0] row_arr = list(range(1, cone_size)) col_arr = list(range(cone_size - 1)) X_mat = sp.coo_matrix((val_arr, (row_arr, col_arr)), mat_shape).tocsc() X_mat = lu.create_const(X_mat, mat_shape, sparse=True) mul_shape = (cone_size, X.shape[1]) terms += [lu.mul_expr(X_mat, X, mul_shape)] return [lu.create_geq(lu.sum_expr(terms))]
def graph_implementation(arg_objs, size, data=None): """Sum the linear expressions. Parameters ---------- arg_objs : list LinExpr for each argument. size : tuple The size of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) """ return (lu.sum_expr(arg_objs), [])
def graph_implementation(arg_objs, size, data=None): """Reduces the atom to an affine expression and list of constraints. Parameters ---------- arg_objs : list LinExpr for each argument. size : tuple The size of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) """ x = arg_objs[0] ones = lu.create_const(np.mat(np.ones(x.size)), x.size) xp1 = lu.sum_expr([x, ones]) return log.graph_implementation([xp1], size, data)
def graph_implementation(arg_objs, shape, data=None): """Reduces the atom to an affine expression and list of constraints. Parameters ---------- arg_objs : list LinExpr for each argument. shape : tuple The shape of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) """ x = arg_objs[0] ones = lu.create_const(np.mat(np.ones(x.shape)), x.shape) xp1 = lu.sum_expr([x, ones]) return log.graph_implementation([xp1], shape, data)
def graph_implementation(arg_objs, size, data=None): """Sum the linear expressions. Parameters ---------- arg_objs : list LinExpr for each argument. size : tuple The size of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) """ for i, arg in enumerate(arg_objs): if arg.size != size: arg_objs[i] = lu.promote(arg, size) return (lu.sum_expr(arg_objs), [])
def graph_implementation(arg_objs, size, data=None): """Reduces the atom to an affine expression and list of constraints. Parameters ---------- arg_objs : list LinExpr for each argument. size : tuple The size of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) """ x = arg_objs[0] t = lu.create_var((1, 1)) promoted_t = lu.promote(t, x.size) constraints = [lu.create_geq(lu.sum_expr([x, promoted_t])), lu.create_leq(x, promoted_t)] return (t, constraints)
def graph_implementation(arg_objs, size, data=None): """Reduces the atom to an affine expression and list of constraints. Parameters ---------- arg_objs : list LinExpr for each argument. size : tuple The size of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) """ A = arg_objs[0] rows, cols = A.size # Create the equivalent problem: # minimize (trace(U) + trace(V))/2 # subject to: # [U A; A.T V] is positive semidefinite X = lu.create_var((rows + cols, rows + cols)) # Expand A.T. obj, constraints = transpose.graph_implementation([A], (cols, rows)) # Fix X using the fact that A must be affine by the DCP rules. # X[0:rows,rows:rows+cols] == A index.block_eq(X, A, constraints, 0, rows, rows, rows + cols) # X[rows:rows+cols,0:rows] == A.T index.block_eq(X, obj, constraints, rows, rows + cols, 0, rows) diag = [ index.get_index(X, constraints, i, i) for i in range(rows + cols) ] half = lu.create_const(0.5, (1, 1)) trace = lu.mul_expr(half, lu.sum_expr(diag), (1, 1)) # Add SDP constraint. return (trace, [SDP(X)] + constraints)
def format_axis(t, X, axis): """Formats all the row/column cones for the solver. Parameters ---------- t: The scalar part of the second-order constraint. X: A matrix whose rows/columns are each a cone. axis: Slice by column 0 or row 1. Returns ------- list A list of LinLeqConstr that represent all the elementwise cones. """ # Reduce to norms of columns. if axis == 1: X = lu.transpose(X) # Create matrices Tmat, Xmat such that Tmat*t + Xmat*X # gives the format for the elementwise cone constraints. num_cones = t.size[0] cone_size = 1 + X.size[0] terms = [] # Make t_mat mat_size = (cone_size, 1) prod_size = (cone_size, t.size[0]) t_mat = sp.coo_matrix(([1.0], ([0], [0])), mat_size).tocsc() t_mat = lu.create_const(t_mat, mat_size, sparse=True) terms += [lu.mul_expr(t_mat, lu.transpose(t), prod_size)] # Make X_mat mat_size = (cone_size, X.size[0]) prod_size = (cone_size, X.size[1]) val_arr = (cone_size - 1)*[1.0] row_arr = range(1, cone_size) col_arr = range(cone_size-1) X_mat = sp.coo_matrix((val_arr, (row_arr, col_arr)), mat_size).tocsc() X_mat = lu.create_const(X_mat, mat_size, sparse=True) terms += [lu.mul_expr(X_mat, X, prod_size)] return [lu.create_geq(lu.sum_expr(terms))]
def graph_implementation(arg_objs, size, data=None): """Reduces the atom to an affine expression and list of constraints. Parameters ---------- arg_objs : list LinExpr for each argument. size : tuple The size of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) """ A = arg_objs[0] rows, cols = A.size # Create the equivalent problem: # minimize (trace(U) + trace(V))/2 # subject to: # [U A; A.T V] is positive semidefinite X = lu.create_var((rows+cols, rows+cols)) # Expand A.T. obj, constraints = transpose.graph_implementation([A], (cols, rows)) # Fix X using the fact that A must be affine by the DCP rules. # X[0:rows,rows:rows+cols] == A index.block_eq(X, A, constraints, 0, rows, rows, rows+cols) # X[rows:rows+cols,0:rows] == A.T index.block_eq(X, obj, constraints, rows, rows+cols, 0, rows) diag = [index.get_index(X, constraints, i, i) for i in range(rows+cols)] half = lu.create_const(0.5, (1, 1)) trace = lu.mul_expr(half, lu.sum_expr(diag), (1, 1)) # Add SDP constraint. return (trace, [SDP(X)] + constraints)
def format_elemwise(vars_): """Formats all the elementwise cones for the solver. Parameters ---------- vars_ : list A list of the LinOp expressions in the elementwise cones. Returns ------- list A list of LinLeqConstr that represent all the elementwise cones. """ # Create matrices Ai such that 0 <= A0*x0 + ... + An*xn # gives the format for the elementwise cone constraints. spacing = len(vars_) # Matrix spaces out columns of the LinOp expressions. mat_shape = (spacing * vars_[0].shape[0], vars_[0].shape[0]) terms = [] for i, var in enumerate(vars_): mat = get_spacing_matrix(mat_shape, spacing, i) terms.append(lu.mul_expr(mat, var)) return [lu.create_geq(lu.sum_expr(terms))]
def graph_implementation(self, arg_objs, shape: Tuple[int, ...], data=None) -> Tuple[lo.LinOp, List[Constraint]]: """Sum the linear expressions. Parameters ---------- arg_objs : list LinExpr for each argument. shape : tuple The shape of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) """ for i, arg in enumerate(arg_objs): if arg.shape != shape and lu.is_scalar(arg): arg_objs[i] = lu.promote(arg, shape) return (lu.sum_expr(arg_objs), [])
def format_elemwise(vars_): """Formats all the elementwise cones for the solver. Parameters ---------- vars_ : list A list of the LinOp expressions in the elementwise cones. Returns ------- list A list of LinLeqConstr that represent all the elementwise cones. """ # Create matrices Ai such that 0 <= A0*x0 + ... + An*xn # gives the format for the elementwise cone constraints. spacing = len(vars_) prod_size = (spacing*vars_[0].size[0], vars_[0].size[1]) # Matrix spaces out columns of the LinOp expressions. mat_size = (spacing*vars_[0].size[0], vars_[0].size[0]) terms = [] for i, var in enumerate(vars_): mat = get_spacing_matrix(mat_size, spacing, i) terms.append(lu.mul_expr(mat, var, prod_size)) return [lu.create_geq(lu.sum_expr(terms))]
def gm(t, x, y): return SOC_Elemwise(lu.sum_expr([x, y]), [lu.sub_expr(x, y), lu.mul_expr(two, t, t.size)])
def graph_implementation(arg_objs, size, data=None): """Reduces the atom to an affine expression and list of constraints. Creates the equivalent problem:: maximize sum(log(D[i, i])) subject to: D diagonal diag(D) = diag(Z) Z is upper triangular. [D Z; Z.T A] is positive semidefinite The problem computes the LDL factorization: .. math:: A = (Z^TD^{-1})D(D^{-1}Z) This follows from the inequality: .. math:: \det(A) >= \det(D) + \det([D, Z; Z^T, A])/\det(D) >= \det(D) because (Z^TD^{-1})D(D^{-1}Z) is a feasible D, Z that achieves det(A) = det(D) and the objective maximizes det(D). Parameters ---------- arg_objs : list LinExpr for each argument. size : tuple The size of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) """ A = arg_objs[0] # n by n matrix. n, _ = A.size X = lu.create_var((2 * n, 2 * n)) Z = lu.create_var((n, n)) D = lu.create_var((n, n)) # Require that X is symmetric (which implies # A is symmetric). # X == X.T obj, constraints = transpose.graph_implementation([X], (n, n)) constraints.append(lu.create_eq(X, obj)) # Require that X and A are PSD. constraints += [SDP(X), SDP(A)] # Fix Z as upper triangular, D as diagonal, # and diag(D) as diag(Z). for i in xrange(n): for j in xrange(n): if i == j: # D[i, j] == Z[i, j] Dij = index.get_index(D, constraints, i, j) Zij = index.get_index(Z, constraints, i, j) constraints.append(lu.create_eq(Dij, Zij)) if i != j: # D[i, j] == 0 Dij = index.get_index(D, constraints, i, j) constraints.append(lu.create_eq(Dij)) if i > j: # Z[i, j] == 0 Zij = index.get_index(Z, constraints, i, j) constraints.append(lu.create_eq(Zij)) # Fix X using the fact that A must be affine by the DCP rules. # X[0:n, 0:n] == D index.block_eq(X, D, constraints, 0, n, 0, n) # X[0:n, n:2*n] == Z, index.block_eq(X, Z, constraints, 0, n, n, 2 * n) # X[n:2*n, n:2*n] == A index.block_eq(X, A, constraints, n, 2 * n, n, 2 * n) # Add the objective sum(log(D[i, i]) log_diag = [] for i in xrange(n): Dii = index.get_index(D, constraints, i, i) obj, constr = log.graph_implementation([Dii], (1, 1)) constraints += constr log_diag.append(obj) obj = lu.sum_expr(log_diag) return (obj, constraints)
def graph_implementation(arg_objs, size, data=None): r"""Reduces the atom to an affine expression and list of constraints. Parameters ---------- arg_objs : list LinExpr for each argument. size : tuple The size of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) Notes ----- Implementation notes. For general ``p``, the p-norm is equivalent to the following convex inequalities: .. math:: x_i &\leq r_i\\ -x_i &\leq r_i\\ r_i &\leq s_i^{1/p} t^{1 - 1/p}\\ \sum_i s_i &\leq t, where :math:`p \geq 1`. These inequalities are also correct for :math:`p = +\infty` if we interpret :math:`1/\infty` as :math:`0`. Although the inequalities above are correct, for a few special cases, we can represent the p-norm more efficiently and with fewer variables and inequalities. - For :math:`p = 1`, we use the representation .. math:: x_i &\leq r_i\\ -x_i &\leq r_i\\ \sum_i r_i &\leq t - For :math:`p = \infty`, we use the representation .. math:: x_i &\leq t\\ -x_i &\leq t Note that we don't need the :math:`s` variables or the sum inequality. - For :math:`p = 2`, we use the natural second-order cone representation .. math:: \|x\|_2 \leq t Note that we could have used the set of inequalities given above if we wanted an alternate decomposition of a large second-order cone into into several smaller inequalities. """ p, w = data x = arg_objs[0] t = None # dummy value so linter won't complain about initialization if p != 1: t = lu.create_var((1, 1)) if p == 2: return t, [SOC(t, [x])] if p == np.inf: r = lu.promote(t, x.size) else: r = lu.create_var(x.size) constraints = [lu.create_geq(lu.sum_expr([x, r])), lu.create_leq(x, r)] if p == 1: return lu.sum_entries(r), constraints if p == np.inf: return t, constraints # otherwise do case of general p s = lu.create_var(x.size) # todo: no need to run gm_constr to form the tree each time. we only need to form the tree once constraints += gm_constrs(r, [s, lu.promote(t, x.size)], w) constraints += [lu.create_leq(lu.sum_entries(s), t)] return t, constraints
def graph_implementation(arg_objs, size, data=None): r"""Reduces the atom to an affine expression and list of constraints. Parameters ---------- arg_objs : list LinExpr for each argument. size : tuple The size of the resulting expression. data : Additional data required by the atom. Returns ------- tuple (LinOp for objective, list of constraints) Notes ----- Implementation notes. - For general :math:`p \geq 1`, the inequality :math:`\|x\|_p \leq t` is equivalent to the following convex inequalities: .. math:: |x_i| &\leq r_i^{1/p} t^{1 - 1/p}\\ \sum_i r_i &= t. These inequalities happen to also be correct for :math:`p = +\infty`, if we interpret :math:`1/\infty` as :math:`0`. - For general :math:`0 < p < 1`, the inequality :math:`\|x\|_p \geq t` is equivalent to the following convex inequalities: .. math:: r_i &\leq x_i^{p} t^{1 - p}\\ \sum_i r_i &= t. - For general :math:`p < 0`, the inequality :math:`\|x\|_p \geq t` is equivalent to the following convex inequalities: .. math:: t &\leq x_i^{-p/(1-p)} r_i^{1/(1 - p)}\\ \sum_i r_i &= t. Although the inequalities above are correct, for a few special cases, we can represent the p-norm more efficiently and with fewer variables and inequalities. - For :math:`p = 1`, we use the representation .. math:: x_i &\leq r_i\\ -x_i &\leq r_i\\ \sum_i r_i &= t - For :math:`p = \infty`, we use the representation .. math:: x_i &\leq t\\ -x_i &\leq t Note that we don't need the :math:`r` variable or the sum inequality. - For :math:`p = 2`, we use the natural second-order cone representation .. math:: \|x\|_2 \leq t Note that we could have used the set of inequalities given above if we wanted an alternate decomposition of a large second-order cone into into several smaller inequalities. """ p = data[0] x = arg_objs[0] t = lu.create_var((1, 1)) constraints = [] # first, take care of the special cases of p = 2, inf, and 1 if p == 2: return t, [SOC(t, [x])] if p == np.inf: t_ = lu.promote(t, x.size) return t, [lu.create_leq(x, t_), lu.create_geq(lu.sum_expr([x, t_]))] # we need an absolute value constraint for the symmetric convex branches (p >= 1) # we alias |x| as x from this point forward to make the code pretty :) if p >= 1: absx = lu.create_var(x.size) constraints += [lu.create_leq(x, absx), lu.create_geq(lu.sum_expr([x, absx]))] x = absx if p == 1: return lu.sum_entries(x), constraints # now, we take care of the remaining convex and concave branches # to create the rational powers, we need a new variable, r, and # the constraint sum(r) == t r = lu.create_var(x.size) t_ = lu.promote(t, x.size) constraints += [lu.create_eq(lu.sum_entries(r), t)] # make p a fraction so that the input weight to gm_constrs # is a nice tuple of fractions. p = Fraction(p) if p < 0: constraints += gm_constrs(t_, [x, r], (-p / (1 - p), 1 / (1 - p))) if 0 < p < 1: constraints += gm_constrs(r, [x, t_], (p, 1 - p)) if p > 1: constraints += gm_constrs(x, [r, t_], (1 / p, 1 - 1 / p)) return t, constraints