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] # n by m matrix. P = arg_objs[1] # n by n matrix. n, m = X.size # Create a matrix with Schur complement T - X.T*P^-1*X. M = lu.create_var((n + m, n + m)) T = lu.create_var((m, m)) constraints = [] # Fix M using the fact that P must be affine by the DCP rules. # M[0:n, 0:n] == P. index.block_eq(M, P, constraints, 0, n, 0, n) # M[0:n, n:n+m] == X index.block_eq(M, X, constraints, 0, n, n, n + m) # M[n:n+m, n:n+m] == T index.block_eq(M, T, constraints, n, n + m, n, n + m) # Add SDP constraint. return (lu.trace(T), constraints + [SDP(M)])
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] P = arg_objs[1] # n by n matrix. n, _ = P.size # Create a matrix with Schur complement t - x.T*P^-1*x. M = lu.create_var((n + 1, n + 1)) t = lu.create_var((1, 1)) constraints = [] # Fix M using the fact that P must be affine by the DCP rules. # M[0:n, 0:n] == P. index.block_eq(M, P, constraints, 0, n, 0, n) # M[0:n, n:n+1] == x index.block_eq(M, x, constraints, 0, n, n, n + 1) # M[n:n+1, n:n+1] == t index.block_eq(M, t, constraints, n, n + 1, n, n + 1) # Add SDP constraint. return (t, constraints + [SDP(M)])
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) """ axis = data[0] if axis is None: t = lu.create_var((1, 1)) promoted_t = lu.promote(t, arg_objs[0].size) elif axis == 0: t = lu.create_var((1, arg_objs[0].size[1])) const_size = (arg_objs[0].size[0], 1) ones = lu.create_const(np.ones(const_size), const_size) promoted_t = lu.mul_expr(ones, t, arg_objs[0].size) else: # axis == 1 t = lu.create_var((arg_objs[0].size[0], 1)) const_size = (1, arg_objs[0].size[1]) ones = lu.create_const(np.ones(const_size), const_size) promoted_t = lu.rmul_expr(t, ones, arg_objs[0].size) constraints = [lu.create_leq(arg_objs[0], 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) """ # 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 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) """ A = arg_objs[0] # n by m matrix. n, m = A.size # Create a matrix with Schur complement I*t - (1/t)*A.T*A. X = lu.create_var((n + m, n + m)) t = lu.create_var((1, 1)) constraints = [] # Fix X using the fact that A must be affine by the DCP rules. # X[0:n, 0:n] == I_n*t prom_t = lu.promote(t, (n, 1)) index.block_eq(X, lu.diag_vec(prom_t), constraints, 0, n, 0, n) # X[0:n, n:n+m] == A index.block_eq(X, A, constraints, 0, n, n, n + m) # X[n:n+m, n:n+m] == I_m*t prom_t = lu.promote(t, (m, 1)) # prom_t = lu.promote(lu.create_const(1, (1,1)), (m, 1)) index.block_eq(X, lu.diag_vec(prom_t), constraints, n, n + m, n, n + m) # Add SDP constraint. return (t, constraints + [SDP(X)])
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 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 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 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) """ # 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) """ A = arg_objs[0] n, _ = A.size # Requires that A is symmetric. obj, constraints = transpose.graph_implementation([A], (n, n)) # A == A.T constraints.append(lu.create_eq(A, obj)) # SDP constraint. t = lu.create_var((1, 1)) prom_t = lu.promote(t, (n, 1)) # I*t - A expr = lu.sub_expr(A, lu.diag_vec(prom_t)) return (t, [SDP(expr)] + 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((1, 1)) # sum(exp(x - t)) prom_t = lu.promote(t, x.size) expr = lu.sub_expr(x, prom_t) obj, constraints = exp.graph_implementation([expr], x.size) obj, constr = sum_entries.graph_implementation([obj], (1, 1)) # obj <= 1 one = lu.create_const(1, (1, 1)) constraints += constr + [lu.create_leq(obj, one)] return (t, constraints)
def graph_implementation(self, arg_objs, shape, data=None): """Cumulative sum via difference matrix. 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) """ # Implicit O(n) definition: # X = Y[1:,:] - Y[:-1, :] Y = lu.create_var(shape) axis = data[0] dim = shape[axis] diff_mat = get_diff_mat(dim, axis) diff_mat = lu.create_const(diff_mat, (dim, dim), sparse=True) if axis == 0: diff = lu.mul_expr(diff_mat, Y) else: diff = lu.rmul_expr(Y, diff_mat) return (Y, [lu.create_eq(arg_objs[0], diff)])
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) """ 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)) constraints = [] # 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) half = lu.create_const(0.5, (1, 1)) trace = lu.mul_expr(half, lu.trace(X), (1, 1)) # Add SDP constraint. return (trace, [SDP(X)] + 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) """ w, w_dyad, tree = data t = lu.create_var((1, 1)) if arg_objs[0].size[1] == 1: x_list = [ index.get_index(arg_objs[0], [], i, 0) for i in range(len(w)) ] if arg_objs[0].size[0] == 1: x_list = [ index.get_index(arg_objs[0], [], 0, i) for i in range(len(w)) ] # todo: catch cases where we have (0, 0, 1)? # todo: what about curvature case (should be affine) in trivial case of (0, 0 , 1), # should this behavior match with what we do in power? return t, gm_constrs(t, x_list, w)
def graph_implementation(arg_objs, size, data=None): """Stack the expressions horizontally. 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 = lu.create_var(size) constraints = [] # Create an equality constraint for each arg. offset = 0 for arg in arg_objs: index.block_eq(X, arg, constraints, 0, size[0], offset, arg.size[1] + offset) offset += arg.size[1] return (X, constraints)
def format(self, eq_constr, leq_constr, dims, solver): """Formats EXP constraints for the solver. Parameters ---------- eq_constr : list A list of the equality constraints in the canonical problem. leq_constr : list A list of the inequality constraints in the canonical problem. dims : dict A dict with the dimensions of the conic constraints. solver : str The solver being called. """ # Need x, y, z to be lone Variables. if solver == s.CVXOPT: constraints = [] for i, var in enumerate(self.vars_): if not var.type is VARIABLE: lone_var = lu.create_var(var.size) constraints.append(lu.create_eq(lone_var, var)) self.vars_[i] = lone_var eq_constr += constraints # Converts to an inequality constraint. elif solver == s.SCS: leq_constr += format_elemwise([self.x, self.y, self.z]) else: raise ValueError("Solver does not support exponential cone.") # Update dims. dims[s.EXP_DIM] += self.size[0]*self.size[1]
def graph_implementation(arg_objs, size, data=None): """Stack the expressions vertically. 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 = lu.create_var(size) constraints = [] # Create an equality constraint for each arg. offset = 0 for arg in arg_objs: index.block_eq(X, arg, constraints, offset, arg.size[0] + offset, 0, size[1]) offset += arg.size[0] return (X, constraints)
def _grad(self, values): """Gives the (sub/super)gradient of the atom w.r.t. each argument. Matrix expressions are vectorized, so the gradient is a matrix. Args: values: A list of numeric values for the arguments. Returns: A list of SciPy CSC sparse matrices or None. """ # TODO should be a simple function in CVXcanon for this. # Make a fake lin op tree for the function. fake_args = [] var_offsets = {} offset = 0 for idx, arg in enumerate(self.args): fake_args += [lu.create_var(arg.size, idx)] var_offsets[idx] = offset offset += arg.size[0] * arg.size[1] fake_expr, _ = self.graph_implementation(fake_args, self.size, self.get_data()) # Get the matrix representation of the function. V, I, J, _ = canonInterface.get_problem_matrix( [lu.create_eq(fake_expr)], var_offsets, None) shape = (offset, self.size[0] * self.size[1]) stacked_grad = sp.coo_matrix((V, (J, I)), shape=shape).tocsc() # Break up into per argument matrices. grad_list = [] start = 0 for idx, arg in enumerate(self.args): stop = start + arg.size[0] * arg.size[1] grad_list += [stacked_grad[start:stop, :]] start = stop return grad_list
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) """ t = lu.create_var(size) constraints = [] for obj in arg_objs: # Promote obj. if obj.size != size: obj = lu.promote(obj, size) constraints.append(lu.create_leq(obj, t)) return (t, constraints)
def graph_implementation(arg_objs, size, data=None): """Cumulative sum via difference matrix. 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) """ # Implicit O(n) definition: # X = Y[:1,:] - Y[1:,:] Y = lu.create_var(size) axis = data[0] dim = size[axis] diff_mat = get_diff_mat(dim, axis) diff_mat = lu.create_const(diff_mat, (dim, dim), sparse=True) if axis == 0: diff = lu.mul_expr(diff_mat, Y, size) else: diff = lu.rmul_expr(Y, diff_mat, size) return (Y, [lu.create_eq(arg_objs[0], diff)])
def __format(self, solver): """Internal version of format with cached results. Returns ------- tuple (equality constraints, inequality constraints) """ eq_constr = [] leq_constr = [] # Need x, y, z to be lone Variables. if solver == s.CVXOPT: constraints = [] for i, var in enumerate(self.vars_): if not var.type is VARIABLE: lone_var = lu.create_var(var.size) constraints.append(lu.create_eq(lone_var, var)) self.vars_[i] = lone_var eq_constr += constraints # Converts to an inequality constraint. elif solver == s.SCS: leq_constr += format_elemwise([self.x, self.y, self.z]) else: raise SolverError("Solver does not support exponential cone.") return (eq_constr, leq_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(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) """ 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)) constraints = [] # 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) half = lu.create_const(0.5, (1, 1)) trace = lu.mul_expr(half, lu.trace(X), (1, 1)) # Add SDP constraint. return (trace, [SDP(X)] + 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 format(self, eq_constr, leq_constr, dims, solver): """Formats EXP constraints for the solver. Parameters ---------- eq_constr : list A list of the equality constraints in the canonical problem. leq_constr : list A list of the inequality constraints in the canonical problem. dims : dict A dict with the dimensions of the conic constraints. solver : str The solver being called. """ # Need x, y, z to be lone Variables. if solver == s.CVXOPT: constraints = [] for i, var in enumerate(self.vars_): if not var.type is VARIABLE: lone_var = lu.create_var(var.size) constraints.append(lu.create_eq(lone_var, var)) self.vars_[i] = lone_var eq_constr += constraints # Converts to an inequality constraint. elif solver == s.SCS: leq_constr += format_elemwise([self.x, self.y, self.z]) else: raise ValueError("Solver does not support exponential cone.") # Update dims. dims[s.EXP_DIM] += self.size[0] * self.size[1]
def graph_implementation(arg_objs, size, data=None): """Convolve two vectors. 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) """ # Implicit O(n) definition: # X = Y[:1,:] - Y[1:,:] Y = lu.create_var(size) axis = data[0] dim = size[axis] diff_mat = get_diff_mat(dim, axis) diff_mat = lu.create_const(diff_mat, (dim, dim), sparse=True) if axis == 0: diff = lu.mul_expr(diff_mat, Y, size) else: diff = lu.rmul_expr(Y, diff_mat, size) return (Y, [lu.create_eq(arg_objs[0], diff)])
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) """ # 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 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) """ w, w_dyad, tree = data t = lu.create_var((1, 1)) if arg_objs[0].size[1] == 1: x_list = [index.get_index(arg_objs[0], [], i, 0) for i in range(len(w))] if arg_objs[0].size[0] == 1: x_list = [index.get_index(arg_objs[0], [], 0, i) for i in range(len(w))] #todo: catch cases where we have (0, 0, 1)? #todo: what about curvature case (should be affine) in trivial case of (0, 0 , 1), should this behavior match with what we do in power? return t, gm_constrs(t, x_list, w)
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) """ 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) """ A = arg_objs[0] n, _ = A.size # SDP constraint. t = lu.create_var((1, 1)) prom_t = lu.promote(t, (n, 1)) # I*t - A expr = lu.sub_expr(lu.diag_vec(prom_t), A) return (t, [SDP(expr)])
def __init__(self, lin_op): self.lin_op = lin_op # Create a new nonconvex variable unless the lin_op is a variable. if lin_op.type is lo.VARIABLE: self.noncvx_var = lin_op else: self.noncvx_var = lu.create_var(self.lin_op.size) super(BoolConstr, self).__init__()
def canonicalize(self): """Returns the graph implementation of the object. Returns: A tuple of (affine expression, [constraints]). """ obj = lu.create_var(self.size, self.id) return (obj, [])
def test_variables(self): """Test creating a variable. """ var = create_var((5, 4), var_id=1) self.assertEqual(var.shape, (5, 4)) self.assertEqual(var.data, 1) self.assertEqual(len(var.args), 0) self.assertEqual(var.type, VARIABLE)
def __CVXOPT_format(self): constraints = [] for i, var in enumerate(self.vars_): if not var.type is VARIABLE: lone_var = lu.create_var(var.size) constraints.append(lu.create_eq(lone_var, var)) self.vars_[i] = lone_var return (constraints, [])
def canonicalize(self): """Variable must be semidefinite and symmetric. """ upper_tri = lu.create_var((self.size[0], 1), self.id) fill_coeff = upper_tri_to_full(self.n) fill_coeff = lu.create_const(fill_coeff, (self.n*self.n, self.size[0]), sparse=True) full_mat = lu.mul_expr(fill_coeff, upper_tri, (self.n*self.n, 1)) full_mat = lu.reshape(full_mat, (self.n, self.n)) return (upper_tri, [SDP(full_mat, enforce_sym=False)])
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] axis = data[0] t = lu.create_var(size) # sum(exp(x - t)) <= 1 if axis is None: prom_t = lu.promote(t, x.size) expr = lu.sub_expr(x, prom_t) obj, constraints = exp.graph_implementation([expr], x.size) obj = lu.sum_entries(obj) elif axis == 0: prom_size = (x.size[0], 1) ones = lu.create_const(np.ones(prom_size), prom_size) prom_t = lu.mul_expr(ones, t, x.size) expr = lu.sub_expr(x, prom_t) obj, constraints = exp.graph_implementation([expr], x.size) const_size = (1, x.size[0]) ones = lu.create_const(np.ones(const_size), const_size) obj = lu.mul_expr(ones, obj, size) else: # axis == 1 prom_size = (1, x.size[1]) ones = lu.create_const(np.ones(prom_size), prom_size) prom_t = lu.rmul_expr(t, ones, x.size) expr = lu.sub_expr(x, prom_t) obj, constraints = exp.graph_implementation([expr], x.size) const_size = (x.size[1], 1) ones = lu.create_const(np.ones(const_size), const_size) obj = lu.rmul_expr(obj, ones, size) ones = lu.create_const(np.ones(size), size) constraints += [lu.create_leq(obj, ones)] return (t, constraints)
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 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] # m by n matrix. n, m = A.size # Create a matrix with Schur complement I*t - (1/t)*A.T*A. X = lu.create_var((n+m, n+m)) t = lu.create_var((1, 1)) I_n = lu.create_const(sp.eye(n), (n, n)) I_m = lu.create_const(sp.eye(m), (m, m)) # Expand A.T. obj, constraints = transpose.graph_implementation([A], (m, n)) # Fix X using the fact that A must be affine by the DCP rules. # X[0:n, 0:n] == I_n*t index.block_eq(X, lu.mul_expr(I_n, t, (n, n)), constraints, 0, n, 0, n) # X[0:n, n:n+m] == A index.block_eq(X, A, constraints, 0, n, n, n+m) # X[n:n+m, 0:n] == obj index.block_eq(X, obj, constraints, n, n+m, 0, n) # X[n:n+m, n:n+m] == I_m*t index.block_eq(X, lu.mul_expr(I_m, t, (m, m)), constraints, n, n+m, n, n+m) # Add SDP constraint. return (t, constraints + [SDP(X)])
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 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] # n by m matrix. n, m = A.size # Create a matrix with Schur complement I*t - (1/t)*A.T*A. X = lu.create_var((n+m, n+m)) t = lu.create_var((1, 1)) constraints = [] # Fix X using the fact that A must be affine by the DCP rules. # X[0:n, 0:n] == I_n*t prom_t = lu.promote(t, (n, 1)) index.block_eq(X, lu.diag_vec(prom_t), constraints, 0, n, 0, n) # X[0:n, n:n+m] == A index.block_eq(X, A, constraints, 0, n, n, n+m) # X[n:n+m, n:n+m] == I_m*t prom_t = lu.promote(t, (m, 1)) # prom_t = lu.promote(lu.create_const(1, (1,1)), (m, 1)) index.block_eq(X, lu.diag_vec(prom_t), constraints, n, n+m, n, n+m) # Add SDP constraint. return (t, constraints + [SDP(X)])
def gm_constrs(t, x_list, p): """ Form the internal CXVPY constraints to form the weighted geometric mean t <= x^p. t <= x[0]^p[0] * x[1]^p[1] * ... * x[n]^p[n] where x and t can either be scalar or matrix variables. Parameters ---------- t : cvx.Variable The epigraph variable x_list : list of cvx.Variable objects The vector of input variables. Must be the same length as ``p``. p : list or tuple of ``int`` and ``Fraction`` objects The powers vector. powers must be nonnegative and sum to *exactly* 1. Must be the same length as ``x``. Returns ------- constr : list list of constraints involving elements of x (and possibly t) to form the geometric mean. """ assert is_weight(p) w = dyad_completion(p) tree = decompose(w) d = defaultdict(lambda: lu.create_var(t.size)) d[w] = t if len(x_list) < len(w): x_list += [t] assert len(x_list) == len(w) for i, (p, v) in enumerate(zip(w, x_list)): if p > 0: tmp = [0]*len(w) tmp[i] = 1 d[tuple(tmp)] = v constraints = [] for elem, children in tree.items(): if 1 not in elem: constraints += [gm(d[elem], d[children[0]], d[children[1]])] return constraints