def test_sdp(self): """Test a problem with semidefinite cones. """ a = sp.rand(100, 100, .1, random_state=1) a = a.todense() X = Variable(100, 100) obj = at.norm(X, "nuc") + at.norm(X - a, 'fro') p = Problem(Minimize(obj)) p.solve(solver="SCS")
def test_mult_by_zero(self): """Test multiplication by zero. """ exp = 0 * self.a self.assertEqual(exp.value, 0) obj = Minimize(exp) p = Problem(obj) result = p.solve() self.assertAlmostEqual(result, 0)
def test_large_square(self): """Test large number of variables squared. """ for n in [10, 20, 30, 40, 50]: A = matrix(range(n * n), (n, n)) x = Variable(n, n) p = Problem(Minimize(at.square(x[0, 0])), [x >= A]) result = p.solve() self.assertAlmostEqual(result, 0)
def test_sdp(self): # Ensure sdp constraints enforce transpose. obj = Maximize(self.A[1,0] - self.A[0,1]) p = Problem(obj, [lambda_max(self.A) <= 100, self.A[0,0] == 2, self.A[1,1] == 2, self.A[1,0] == 2]) result = p.solve() self.assertAlmostEqual(result, 0)
def test_multiplication_on_left(self): c = matrix([1,2]) p = Problem(Minimize(c.T*self.A*c), [self.A >= 2]) result = p.solve() self.assertAlmostEqual(result, 18) p = Problem(Minimize(self.a*2), [self.a >= 2]) result = p.solve() self.assertAlmostEqual(result, 4) p = Problem(Minimize(self.x.T*c), [self.x >= 2]) result = p.solve() self.assertAlmostEqual(result, 6) p = Problem(Minimize((self.x.T + self.z.T)*c), [self.x >= 2, self.z >= 1]) result = p.solve() self.assertAlmostEqual(result, 9)
def test_mixed_atoms(self): p = Problem(Minimize(norm2(5 + norm1(self.z) + norm1(self.x) + normInf(self.x - self.z) ) ), [self.x >= [2,3], self.z <= [-1,-4], norm2(self.x + self.z) <= 2]) result = p.solve() self.assertAlmostEqual(result, 22) self.assertItemsAlmostEqual(self.x.value, [2,3]) self.assertItemsAlmostEqual(self.z.value, [-1,-4])
def test_parameters(self): """Test the parameters method. """ p1 = Parameter() p2 = Parameter(3, sign="negative") p3 = Parameter(4, 4, sign="positive") p = Problem(Minimize(p1), [self.a + p1 <= p2, self.b <= p3 + p3 + 2]) params = p.parameters() self.assertItemsEqual(params, [p1, p2, p3])
def test_constant_atoms(): tests = [] for atom_list, objective_type in atoms: for atom, size, args, obj_val in atom_list: for indexer in get_indices(size): for solver in SOLVERS_TO_TRY: # Atoms with Constant arguments. prob_val = obj_val[indexer].value const_args = [Constant(arg) for arg in args] problem = Problem( objective_type(atom(*const_args)[indexer])) yield (run_atom, atom, problem, prob_val, solver) # Atoms with Variable arguments. variables = [] constraints = [] for idx, expr in enumerate(args): variables.append(Variable(intf.shape(expr))) constraints.append(variables[-1] == expr) objective = objective_type(atom(*variables)[indexer]) new_obj_val = prob_val if objective_type == Maximize: objective = -objective new_obj_val = -new_obj_val problem = Problem(objective, constraints) yield (run_atom, atom, problem, new_obj_val, solver) # Atoms with Parameter arguments. parameters = [] for expr in args: parameters.append(Parameter(intf.shape(expr))) parameters[-1].value = intf.DEFAULT_INTF.const_to_matrix(expr) objective = objective_type(atom(*parameters)[indexer]) yield (run_atom, atom, Problem(objective), prob_val, solver)
def test_variable_promotion(self): p = Problem(Minimize(self.a), [self.x <= self.a, self.x == [1,2]]) result = p.solve() self.assertAlmostEqual(result, 2) self.assertAlmostEqual(self.a.value, 2) p = Problem(Minimize(self.a), [self.A <= self.a, self.A == [[1,2],[3,4]] ]) result = p.solve() self.assertAlmostEqual(result, 4) self.assertAlmostEqual(self.a.value, 4) # Promotion must happen before the multiplication. p = Problem(Minimize([[1],[1]]*(self.x + self.a + 1)), [self.a + self.x >= [1,2]]) result = p.solve() self.assertAlmostEqual(result, 5)
def test_variables(self): """Test the variables method. """ p = Problem(Minimize(self.a), [self.a <= self.x, self.b <= self.A + 2]) vars_ = p.variables() ref = [self.a, self.x, self.b, self.A] if PY2: self.assertItemsEqual(vars_, ref) else: self.assertCountEqual(vars_, ref)
def test_qp_maximization_reduction_path_ecos(self): qp_maximization = Problem(Maximize(-sum_squares(self.x)), [self.x <= -1]) self.assertTrue(qp_maximization.is_dcp()) path = PathFinder().reduction_path(ProblemType(qp_maximization), [ECOS]) self.assertEquals(4, len(path)) self.assertEquals(path[1], ConeMatrixStuffing) self.assertEquals(path[2], Dcp2Cone) self.assertEquals(path[3], FlipObjective)
def test_vector_lp(self): c = matrix([1, 2]) p = Problem(Minimize(c.T * self.x), [self.x >= c]) result = p.solve() self.assertAlmostEqual(result, 5) self.assertItemsAlmostEqual(self.x.value, [1, 2]) A = matrix([[3, 5], [1, 2]]) I = Constant([[1, 0], [0, 1]]) p = Problem(Minimize(c.T * self.x + self.a), [ A * self.x >= [-1, 1], 4 * I * self.z == self.x, self.z >= [2, 2], self.a >= 2 ]) result = p.solve() self.assertAlmostEqual(result, 26, places=3) obj = c.T * self.x.value + self.a.value self.assertAlmostEqual(obj[0, 0], result) self.assertItemsAlmostEqual(self.x.value, [8, 8], places=3) self.assertItemsAlmostEqual(self.z.value, [2, 2], places=3)
def test_sdp(self) -> None: """Test a problem with semidefinite cones. """ self.skipTest("Too slow.") a = sp.rand(100, 100, .1, random_state=1) a = a.todense() X = Variable((100, 100)) obj = at.norm(X, "nuc") + at.norm(X - a, 'fro') p = Problem(cp.Minimize(obj)) p.solve(solver="SCS")
def test_matrix_lp(self): T = matrix(1, (2, 2)) p = Problem(Minimize(1), [self.A == T]) result = p.solve() self.assertAlmostEqual(result, 1) self.assertItemsAlmostEqual(self.A.value, T) T = matrix(2, (2, 3)) c = matrix([3, 4]) p = Problem(Minimize(1), [self.A >= T * self.C, self.A == self.B, self.C == T.T]) result = p.solve() self.assertAlmostEqual(result, 1) self.assertItemsAlmostEqual(self.A.value, self.B.value) self.assertItemsAlmostEqual(self.C.value, T) assert (self.A.value >= T * self.C.value).all() # Test variables are dense. self.assertEqual(type(self.A.value), p._DENSE_INTF.TARGET_MATRIX)
def test_duplicate_constraints(self): eq = (self.x == 2) le = (self.x <= 2) obj = 0 def test(self): objective, constr_map, dims, solver = self.canonicalize(s.ECOS) return (len(constr_map[s.EQ]), len(constr_map[s.LEQ])) Problem.register_solve("test", test) p = Problem(Minimize(obj), [eq, eq, le, le]) result = p.solve(method="test") self.assertEqual(result, (1, 1)) # Internal constraints. z = hstack(self.x, self.x) obj = sum_entries(z[:, 0] + z[:, 1]) p = Problem(Minimize(obj)) result = p.solve(method="test") self.assertEqual(result, (2, 0))
def test_large_square(self): """Test large number of variables squared. """ self.skipTest("Too slow.") for n in [10, 20, 30, 40, 50]: A = np.arange(n * n) A = np.reshape(A, (n, n)) x = Variable((n, n)) p = Problem(cp.Minimize(at.square(x[0, 0])), [x >= A]) result = p.solve() self.assertAlmostEqual(result, 0)
def test_vec(self): """Tests problems with vec. """ c = [1, 2, 3, 4] expr = vec(self.A) obj = Minimize(expr.T * c) constraints = [self.A == [[-1, -2], [3, 4]]] prob = Problem(obj, constraints) result = prob.solve() self.assertAlmostEqual(result, 20) self.assertItemsAlmostEqual(expr.value, [-1, -2, 3, 4])
def test_diag_prob(self): """Test a problem with diag. """ C = Variable(3, 3) obj = Maximize(C[0, 2]) constraints = [ diag(C) == 1, C[0, 1] == 0.6, C[1, 2] == -0.3, C == Semidef(3) ] prob = Problem(obj, constraints) result = prob.solve() self.assertAlmostEqual(result, 0.583151)
def test_presolve_constant_constraints(self): """Test that the presolver removes constraints with no variables. """ x = Variable() obj = Maximize(sqrt(x)) prob = Problem(obj) c, G, h, dims, A, b = prob.get_problem_data(s.ECOS) for row in range(A.shape[0]): assert A[row, :].nnz > 0 for row in range(G.shape[0]): assert G[row, :].nnz > 0
def test_large_sum(self): """Test large number of variables summed. """ for n in [10, 20, 30, 40, 50]: A = matrix(range(n * n), (n, n)) x = Variable(n, n) p = Problem(Minimize(at.sum_entries(x)), [x >= A]) result = p.solve() answer = n * n * (n * n + 1) / 2 - n * n print result - answer self.assertAlmostEqual(result, answer)
def test_transpose(self): p = Problem(Minimize(sum_entries(self.x)), [self.x.T >= matrix([1,2]).T]) result = p.solve() self.assertAlmostEqual(result, 3) self.assertItemsAlmostEqual(self.x.value, [1,2]) p = Problem(Minimize(sum_entries(self.C)), [matrix([1,1]).T*self.C.T >= matrix([0,1,2]).T]) result = p.solve() value = self.C.value constraints = [1*self.C[i,0] + 1*self.C[i,1] >= i for i in range(3)] p = Problem(Minimize(sum_entries(self.C)), constraints) result2 = p.solve() self.assertAlmostEqual(result, result2) self.assertItemsAlmostEqual(self.C.value, value) p = Problem(Minimize(self.A[0,1] - self.A.T[1,0]), [self.A == [[1,2],[3,4]]]) result = p.solve() self.assertAlmostEqual(result, 0) exp = (-self.x).T p = Problem(Minimize(sum_entries(self.x)), [(-self.x).T <= 1]) result = p.solve() self.assertAlmostEqual(result, -2) c = matrix([1,-1]) p = Problem(Minimize(max_elemwise(c.T, 2, 2 + c.T)[1])) result = p.solve() self.assertAlmostEqual(result, 2) c = matrix([[1,-1,2],[1,-1,2]]) p = Problem(Minimize(sum_entries(max_elemwise(c, 2, 2 + c).T[:,0]))) result = p.solve() self.assertAlmostEqual(result, 6) c = matrix([[1,-1,2],[1,-1,2]]) p = Problem(Minimize(sum_entries(square(c.T).T[:,0]))) result = p.solve() self.assertAlmostEqual(result, 6) # Slice of transpose. p = Problem(Maximize(sum_entries(self.C)), [self.C.T[:,1:3] <= 2, self.C.T[:,0] == 1]) result = p.solve() self.assertAlmostEqual(result, 10) self.assertItemsAlmostEqual(self.C.value, 2*[1,2,2])
def test_parameter_problems(self): """Test problems with parameters. """ p1 = Parameter() p2 = Parameter(3, sign="negative") p3 = Parameter(4, 4, sign="positive") p = Problem(Maximize(p1*self.a), [self.a + p1 <= p2, self.b <= p3 + p3 + 2]) p1.value = 2 p2.value = -numpy.ones((3,1)) p3.value = numpy.ones((4, 4)) result = p.solve() self.assertAlmostEqual(result, -6)
def test_large_sdp(self): """Test for bug where large PSD caused integer overflow in cvxcore. """ SHAPE = (256, 256) rows = SHAPE[0] cols = SHAPE[1] X = Variable(SHAPE) Z = Variable((rows+cols, rows+cols)) prob = Problem(Minimize(0.5*at.trace(Z)), [X[0, 0] >= 1, Z[0:rows, rows:rows+cols] == X, Z >> 0, Z == Z.T]) prob.solve(solver="SCS") self.assertAlmostEqual(prob.value, 1.0)
def _value_impl(self): from cvxpy.problems.problem import Problem from cvxpy.problems.objective import Maximize y_val = self.args[0].value.round(decimals=9).ravel(order='F') x_flat = self._parent.x.flatten() cons = self._parent.constraints if len(cons) == 0: dummy = Variable() cons = [dummy == 1] prob = Problem(Maximize(y_val @ x_flat), cons) val = prob.solve(solver='SCS', eps=1e-6) return val
def test_quad_form(self): with self.assertRaises(Exception) as cm: Problem(Minimize(quad_form(self.x, self.A))).solve() self.assertEqual( str(cm.exception), "At least one argument to quad_form must be constant.") with self.assertRaises(Exception) as cm: Problem(Minimize(quad_form(1, self.A))).solve() self.assertEqual(str(cm.exception), "Invalid dimensions for arguments.") with self.assertRaises(Exception) as cm: Problem(Minimize(quad_form(self.x, [[-1, 0], [0, 9]]))).solve() self.assertEqual(str(cm.exception), "P has both positive and negative eigenvalues.") P = [[4, 0], [0, 9]] p = Problem(Minimize(quad_form(self.x, P)), [self.x >= 1]) result = p.solve() self.assertAlmostEqual(result, 13, places=3) c = [1, 2] p = Problem(Minimize(quad_form(c, self.A)), [self.A >= 1]) result = p.solve() self.assertAlmostEqual(result, 9) c = [1, 2] P = [[4, 0], [0, 9]] p = Problem(Minimize(quad_form(c, P))) result = p.solve() self.assertAlmostEqual(result, 40)
def grad(self): """Gives the (sub/super)gradient of the expression w.r.t. each variable. Matrix expressions are vectorized, so the gradient is a matrix. None indicates variable values unknown or outside domain. Returns: A map of variable to SciPy CSC sparse matrix or None. """ # Subgrad of g(y) = min f_0(x,y) # s.t. f_i(x,y) <= 0, i = 1,..,p # h_i(x,y) == 0, i = 1,...,q # Given by Df_0(x^*,y) + \sum_i Df_i(x^*,y) \lambda^*_i # + \sum_i Dh_i(x^*,y) \nu^*_i # where x^*, \lambda^*_i, \nu^*_i are optimal primal/dual variables. # Add PSD constraints in same way. # Short circuit for constant. if self.is_constant(): return u.grad.constant_grad(self) old_vals = {var.id: var.value for var in self.variables()} fix_vars = [] for var in self.dont_opt_vars: if var.value is None: return u.grad.error_grad(self) else: fix_vars += [var == var.value] prob = Problem(self.args[0].objective, fix_vars + self.args[0].constraints) prob.solve(verbose=True) # Compute gradient. if prob.status in s.SOLUTION_PRESENT: sign = self.is_convex() - self.is_concave() # Form Lagrangian. lagr = self.args[0].objective.args[0] for constr in self.args[0].constraints: # TODO: better way to get constraint expressions. lagr_multiplier = self.cast_to_const(sign*constr.dual_value) prod = lagr_multiplier.T*constr.expr if prod.is_scalar(): lagr += sum(prod) else: lagr += trace(prod) grad_map = lagr.grad result = {var: grad_map[var] for var in self.dont_opt_vars} else: # Unbounded, infeasible, or solver error. result = u.grad.error_grad(self) # Restore the original values to the variables. for var in self.variables(): var.value = old_vals[var.id] return result
def test_duplicate_constraints(self): eq = (self.x == 2) le = (self.x <= 2) obj = 0 def test(self): objective, constr_map, dims = self.canonicalize() return (len(constr_map[s.EQ]), len(constr_map[s.INEQ])) Problem.register_solve("test", test) p = Problem(Minimize(obj), [eq, eq, le, le]) result = p.solve(method="test") self.assertEqual(result, (1, 1))
def test_constant_atoms(atom_info, objective_type) -> None: atom, size, args, obj_val = atom_info for indexer in get_indices(size): for solver in SOLVERS_TO_TRY: # Atoms with Constant arguments. prob_val = obj_val[indexer].value const_args = [Constant(arg) for arg in args] if len(size) != 0: objective = objective_type(atom(*const_args)[indexer]) else: objective = objective_type(atom(*const_args)) problem = Problem(objective) run_atom(atom, problem, prob_val, solver) # Atoms with Variable arguments. variables = [] constraints = [] for idx, expr in enumerate(args): variables.append(Variable(intf.shape(expr))) constraints.append(variables[-1] == expr) if len(size) != 0: objective = objective_type(atom(*variables)[indexer]) else: objective = objective_type(atom(*variables)) problem = Problem(objective, constraints) run_atom(atom, problem, prob_val, solver) # Atoms with Parameter arguments. parameters = [] for expr in args: parameters.append(Parameter(intf.shape(expr))) parameters[-1].value = intf.DEFAULT_INTF.const_to_matrix(expr) if len(size) != 0: objective = objective_type(atom(*parameters)[indexer]) else: objective = objective_type(atom(*parameters)) run_atom(atom, Problem(objective), prob_val, solver)
def __init__(self, prob, opt_vars, dont_opt_vars): self.opt_vars = opt_vars self.dont_opt_vars = dont_opt_vars self.args = [prob] # Replace the opt_vars in prob with new variables. id_to_new_var = {var.id: var.copy() for var in self.opt_vars} new_obj = self._replace_new_vars(prob.objective, id_to_new_var) new_constrs = [ self._replace_new_vars(con, id_to_new_var) for con in prob.constraints ] self._prob = Problem(new_obj, new_constrs) super(PartialProblem, self).__init__()
def test_large_sum(self): """Test large number of variables summed. """ self.skipTest("Too slow.") for n in [10, 20, 30, 40, 50]: A = np.arange(n * n) A = np.reshape(A, (n, n)) x = Variable((n, n)) p = Problem(cp.Minimize(at.sum(x)), [x >= A]) result = p.solve() answer = n * n * (n * n + 1) / 2 - n * n print(result - answer) self.assertAlmostEqual(result, answer)