def test_pcp_2(self): # TODO: reformulate with SolverTestHelper """ Reformulate max (x**0.2)*(y**0.8) + z**0.4 - x s.t. x + y + z/2 == 2 x, y, z >= 0 Into max x3 + x4 - x0 s.t. x0 + x1 + x2 / 2 == 2, (x0, x1, x3) in Pow3D(0.2) (x2, 1.0, x4) in Pow3D(0.4) """ x = cl.Variable(shape=(3,)) hypos = cl.Variable(shape=(2,)) objective = -cl.sum(hypos) + x[0] con1_expr = cl.hstack((x[0], x[1], hypos[0])) con1_weights = np.array([0.2, 0.8, -1.0]) con2_expr = cl.hstack((x[2], 1.0, hypos[1])) con2_weights = np.array([0.4, 0.6, -1.0]) constraints = [ x[0] + x[1] + 0.5 * x[2] == 2, PowCone(con1_expr, con1_weights), PowCone(con2_expr, con2_weights) ] opt_objective = -1.8073406786220672 opt_x = np.array([0.06393515, 0.78320961, 2.30571048]) prob = cl.Problem(cl.MIN, objective, constraints) prob.solve(solver='CP') self.assertAlmostEqual(prob.value, opt_objective) assert np.allclose(x.value, opt_x, atol=1e-3)
def test_pcp_1(self): #TODO: reformulate with SolverTestHelper """ Use a 3D power cone formulation for min 3 * x[0] + 2 * x[1] + x[2] s.t. norm(x,2) <= y x[0] + x[1] + 3*x[2] >= 1.0 y <= 5 """ x = cl.Variable(shape=(3,)) y_square = cl.Variable() epis = cl.Variable(shape=(3,)) constraints = [PowCone(cl.hstack((1.0, x[0], epis[0])), np.array([0.5, -1, 0.5])), PowCone(cl.hstack((1.0, x[1], epis[1])), np.array([0.5, -1, 0.5])), PowCone(cl.hstack((x[2], 1.0, epis[2])), np.array([-1, 0.5, 0.5])), # Could have done PowCone(cl.hstack((1.0, x[2], epis[2])), np.array([0.5, -1, 0.5])). cl.sum(epis) <= y_square, x[0] + x[1] + 3 * x[2] >= 1.0, y_square <= 25] objective = 3 * x[0] + 2 * x[1] + x[2] expect_x = np.array([-3.874621860638774, -2.129788233677883, 2.33480343377204]) expect_epis = expect_x ** 2 expect_x = np.round(expect_x, decimals=5) expect_epis = np.round(expect_epis, decimals=5) expect_y_square = 25 expect_objective = -13.548638904065102 prob = cl.Problem(cl.MIN, objective, constraints) prob.solve(solver='CP') self.assertAlmostEqual(prob.value, expect_objective, delta=1e-4) self.assertAlmostEqual(y_square.value, expect_y_square, delta=1e-4) concat = cl.hstack((x.value, epis.value)) expect_concat = cl.hstack((expect_x, expect_epis)) for i in range(5): self.assertAlmostEqual(concat[i], expect_concat[i], delta=1e-2) pass
def test_redundant_components(self): # create problems where some (but not all) components of a vector variable # participate in the final conic formulation. x = cl.Variable(shape=(4,)) cons = [0 <= x[1:], cl.sum(x[1:]) <= 1] objective = x[1] + 0.5 * x[2] + 0.25 * x[3] prob = cl.Problem(cl.MAX, objective, cons) prob.solve(solver='ECOS', verbose=False) assert np.allclose(x.value, np.array([0, 1, 0, 0])) pass
def test_parse_integer_constraints(self): x = Variable(shape=(3,), name='my_name_x') y = Variable(shape=(3,), name='my_name_y') z = Variable(shape=(3,), name='my_name_z') invalid_lst = [2, 4, 6] self.assertRaises(ValueError, Problem._parse_integer_constraints, x, invalid_lst) valid_lst = [x, y, z] prob = cl.Problem(cl.MIN, cl.sum(x), [x==1, y == 0, z == -1]) prob.variable_map = {'my_name_x': np.array([0, 1]), 'my_name_y': np.array([1, 2]), 'my_name_z': np.array([2, 3]) } prob._parse_integer_constraints(valid_lst) int_indices_expected = [0, 1, 1, 2, 2, 3] assert Expression.are_equivalent(int_indices_expected, prob._integer_indices) prob1 = cl.Problem(cl.MIN, cl.sum(x), [x==1, y == 0, z[:-1] == -1]) self.assertRaises(ValueError, Problem._parse_integer_constraints, prob1, valid_lst) z_part = z[:-1] self.assertRaises(ValueError, Problem._parse_integer_constraints, prob1, [x, y, z_part])
def pcp_4(ceei: bool = True): """ A power cone formulation of a Fisher market equilibrium pricing model. ceei = Competitive Equilibrium from Equal Incomes """ # Generate test data np.random.seed(0) n_buyer = 4 n_items = 6 V = np.random.rand(n_buyer, n_items) X = cl.Variable(shape=(n_buyer, n_items)) u = cl.sum(V * X, axis=1) z = cl.Variable() if ceei: b = np.ones(n_buyer) / n_buyer expect_X = np.array([[9.16311051e-01, 2.71146000e-09, 6.44984275e-10, 0.00000000e+00, 1.85098676e-09, 6.66541059e-01], [0.00000000e+00, 0.00000000e+00, 5.30793141e-01, 0.00000000e+00, 9.99999995e-01, 1.35828851e-09], [9.78080132e-10, 9.99999998e-01, 0.00000000e+00, 0.00000000e+00, 1.16278780e-09, 3.33458937e-01], [8.36889514e-02, 0.00000000e+00, 4.69206858e-01, 1.00000001e+00, 7.80694090e-10, 8.26483799e-10]]) pow_objective = (-z, -1.179743761485325) else: b = np.array([0.3, 0.15, 0.2, 0.35]) expect_X = np.array([[9.08798195e-01, 0.00000000e+00, 0.00000000e+00, 2.67738456e-10, 3.44073780e-09, 9.58119833e-01], [0.00000000e+00, 1.92431554e-10, 3.91981663e-09, 0.00000000e+00, 9.99999991e-01, 0.00000000e+00], [0.00000000e+00, 9.99999993e-01, 0.00000000e+00, 0.00000000e+00, 0.00000000e+00, 4.18801652e-02], [9.12018094e-02, 1.09687013e-08, 1.00000000e+00, 1.00000001e+00, 5.94724468e-09, 6.99603695e-09]]) pow_objective = (-z, -1.2279371987281384) pow_cons = [(cl.sum(X, axis=0) <= 1, None), (PowCone(cl.hstack((u, z)), np.hstack((b, -1))), None), (X >= 0, None)] pow_vars = [(X, expect_X)] sth = SolverTestHelper(pow_objective, pow_vars, pow_cons) return sth
def sage_multiplier_search(f, level=1, X=None): """ Constructs a coniclifts maximization Problem which is feasible if ``f`` can be certified as nonnegative over ``X``, by using an appropriate X-SAGE modulating function. Parameters ---------- f : Polynomial We want to test if ``f`` is nonnegative over ``X``. level : int Controls the complexity of the X-SAGE modulating function. Must be a positive integer. X : PolyDomain or None If ``X`` is None, then we test nonnegativity of ``f`` over :math:`R^{\\texttt{f.n}}`. Returns ------- prob : sageopt.coniclifts.Problem Notes ----- This function provides an alternative to moving up the reference SAGE hierarchy, for the goal of certifying nonnegativity of a polynomial ``f`` over some set ``X`` where ``|X|`` is log-convex. In general, the approach is to introduce a polynomial ``mult = Polynomial(alpha_hat, c_tilde)`` where the rows of alpha_hat are all "level"-wise sums of rows from ``f.alpha``, and ``c_tilde`` is a coniclifts Variable defining a nonzero SAGE polynomial. Then we can check if ``f_mod = f * mult`` is SAGE for any choice of ``c_tilde``. """ constraints = [] # Make the multiplier polynomial (and require that it be SAGE) mult_alpha = hierarchy_e_k([f], k=level) c_tilde = cl.Variable(shape=(mult_alpha.shape[0], ), name='c_tilde') mult = Polynomial(mult_alpha, c_tilde) temp_cons = primal_sage_poly_cone(mult, name=(c_tilde.name + ' domain'), log_AbK=X) constraints += temp_cons constraints.append(cl.sum(c_tilde) >= 1) # Make "f_mod := f * mult", and require that it be SAGE. f_mod = mult * f temp_cons = primal_sage_poly_cone(f_mod, name='f_mod sage poly', log_AbK=X) constraints += temp_cons # noinspection PyTypeChecker prob = cl.Problem(cl.MAX, 0, constraints) if AUTO_CLEAR_INDICES: # pragma:no cover cl.clear_variable_indices() return prob
def test_simple_MILP(self): # Include continuous variables x = cl.Variable() y = cl.Variable((2,)) obj_expr = y[0] # minimize me cont_cons = [cl.sum(y) == x, -1.5 <= x, x <= 2.5, 0 <= y[1], y[1] <= 4.7] prob = cl.Problem(cl.MIN, obj_expr, cont_cons, integer_variables=[x]) prob.solve(solver='MOSEK') # to push y[0] negative, we need to push x to its lower bounds # and y[1] to its upper bound. expect_y = np.array([-5.7, 4.7]) expect_x = -1.0 self.assertAlmostEqual(y[0].value, expect_y[0], places=5) self.assertAlmostEqual(y[1].value, expect_y[1], places=5) self.assertAlmostEqual(x.value, expect_x, places=5) pass
def sage_multiplier_search(f, level=1, X=None): """ Constructs a coniclifts maximization Problem which is feasible if ``f`` can be certified as nonnegative over ``X``, by using an appropriate X-SAGE modulating function. Parameters ---------- f : Signomial We want to test if ``f`` is nonnegative over ``X``. level : int Controls the complexity of the X-SAGE modulating function. Must be a positive integer. X : SigDomain If ``X`` is None, then we test nonnegativity of ``f`` over :math:`R^{\\texttt{f.n}}`. Returns ------- prob : sageopt.coniclifts.Problem Notes ----- This function provides an alternative to moving up the reference SAGE hierarchy, for the goal of certifying nonnegativity of a signomial ``f`` over some convex set ``X``. In general, the approach is to introduce a signomial ``mult = Signomial(alpha_hat, c_tilde)`` where the rows of ``alpha_hat`` are all ``level``-wise sums of rows from ``f.alpha``, and ``c_tilde`` is a coniclifts Variable defining a nonzero X-SAGE function. Then we check if ``f_mod = f * mult`` is X-SAGE for any choice of ``c_tilde``. """ f = f.without_zeros() constraints = [] mult_alpha = hierarchy_e_k([f, f.upcast_to_signomial(1)], k=level) c_tilde = cl.Variable(mult_alpha.shape[0], name='c_tilde') mult = Signomial(mult_alpha, c_tilde) constraints.append(cl.sum(c_tilde) >= 1) sig_under_test = mult * f con1 = primal_sage_cone(mult, name=str(mult), X=X) con2 = primal_sage_cone(sig_under_test, name=str(sig_under_test), X=X) constraints.append(con1) constraints.append(con2) prob = cl.Problem(cl.MAX, cl.Expression([0]), constraints) if AUTO_CLEAR_INDICES: # pragma:no cover cl.clear_variable_indices() return prob