def test_expcone_infer_sigdomain(self): y = standard_sig_monomials(1)[0] dummy_f = y * 0 g0 = 10 - y - y**2 - 1 / y d0 = infer_domain(dummy_f, [g0], []) g1 = y * g0 d1 = infer_domain(dummy_f, [g1], []) g2 = g0 / y**0.5 d2 = infer_domain(dummy_f, [g2], []) for di in [d0, d1, d2]: assert len(di.K) == 4 assert di.K[0].type == '+' assert di.K[0].len == 1 for j in [1, 2, 3]: assert di.K[j].type == 'e' for di in [d0, d1, d2]: A = di.A assert np.allclose(A[0, :], np.array([0, -1, -1, -1])) selector = np.zeros(shape=(A.shape[0], ), dtype=bool) selector[[1, 4, 7]] = True coeffs = np.sort(A[selector, 0]) assert np.allclose(coeffs, np.array([-1, 1, 2])) assert np.allclose(A[~selector, 0], np.zeros(A.shape[0] - 3)) compare = np.zeros(shape=(A.shape[0] - 1, A.shape[1] - 1)) compare[1, 0] = 1 compare[4, 1] = 1 compare[7, 2] = 1 assert np.allclose(A[1:, 1:], compare) pass
def test_conditional_constrained_sage_2(self): # Background # # This is Problem 4 from a 2005 paper by Yanjun Wang and Zhian Liang. # The optimal objective is between 11.95 and 11.96. # # Tests - (p, q, ell) = (0, 2, 0) # # (1) Verify similar primal / dual objectives. # # (2) Verify that primal objective is within 1 percent of a reference value. # # (3) Recover a solution feasible within 1e-8, within 1 percent of optimality. # n = 2 y = standard_sig_monomials(n) f = 3.7 * y[0] ** 0.85 + 1.985 * y[0] + 700.3 * y[1] ** -0.75 gts = [1 - 0.7673 * y[1] ** 0.05 + 0.05 * y[0], 5 - y[0], y[0] - 0.1, 450 - y[1], y[1] - 380] eqs = [] X = infer_domain(f, gts, eqs) p, q, ell = 0, 2, 0 vals, dual = constrained_primal_dual_vals(f, gts, eqs, p, q, ell, X, solver='MOSEK') assert abs(vals[0] - vals[1]) < 1e-1 assert abs(vals[0] - 11.95) / vals[0] < 1e-2 solns = sig_solrec(dual, ineq_tol=1e-8) assert (f(solns[0]) - dual.value) / dual.value < 1e-2
def test_conditional_constrained_sage_1(self): # Background # # This is Problem 1 from a 2014 paper by Xue-Ping Hou, Pei-Ping Shen, and Yong-Qiang Chen. # It can also be found in * many * other papers. # The optimal objective is 0.76508 # # Tests - (p, q, ell) = (0, 1, 0). # # (1) Check that primal and dual objectives are close. # # (2) Check that primal objective is close to reference value. # # (3) Verify that we can recover an optimal solution. # n = 4 y = standard_sig_monomials(n) f = y[2] ** 0.8 * y[3] ** 1.2 gts = [y[0] * y[3] ** -1 + y[1] ** -1 * y[3] ** -1 - 1, - y[0] ** -2 * y[2] ** -1 - y[1] * y[2] ** -1 + 1] gts = [-g for g in gts] gts += [1 - y[0], y[0] - 0.1, 10 - y[1], y[1] - 5, 15 - y[2], y[2] - 8, 1 - y[3], y[3] - 0.01] eqs = [] X = infer_domain(f, gts, eqs) p, q, ell = 0, 1, 0 vals, dual = constrained_primal_dual_vals(f, gts, eqs, p, q, ell, X) assert abs(vals[0] - vals[1]) < 1e-5 assert abs(vals[0] - 0.765082) < 1e-4 solns = sig_solrec(dual, ineq_tol=0) assert f(solns[0]) < 1e-8 + dual.value
def test_freecomponent_infer_sigdomain(self): x = standard_sig_monomials(4) dummy_f = x[0] * 0 gts = [1 - x[1]**0.5 - x[2]**3] dom = infer_domain(dummy_f, gts, []) A, b, K = dom.A, dom.b, dom.K # ^ Two exponential cones, two epigraph variables, one linear inequality assert A.shape == (7, 6) assert len(K) == 3 assert K[0].type == '+' and K[0].len == 1 assert K[1].type == 'e' and K[1].len == 3 assert K[2].type == 'e' and K[2].len == 3 assert np.count_nonzero(A[:, 0]) == 0 assert np.count_nonzero(A[:, 3]) == 0 pass
def test_eqcon_infer_sigdomain(self): y = standard_sig_monomials(3) expx0 = np.exp([1, 2, 3]) eqs = [y[0] - expx0[0], 2*y[1] - 2*expx0[1], 0.5*expx0[2] - 0.5*y[2]] gts = [y[0] - y[1] + y[2]] # not convex f = -np.sum(y) + 1 X = infer_domain(f, gts, eqs) is_in = X.check_membership(np.array([1, 2, 3]), tol=1e-10) assert is_in is_in = X.check_membership(np.array([1.0001, 2, 3]), tol=1e-5) assert not is_in assert X.A.shape == (3, 3) assert all([co.type == '0' for co in X.K]) residual = X.A @ np.array([1, 2, 3]) + X.b assert np.allclose(residual, np.zeros(3))
def test_conditional_sage_1(self): x = standard_poly_monomials(1)[0] f = -x**2 gts = [1 - x**2] opt = -1 X = infer_domain(f, gts, []) res_uncon00 = primal_dual_unconstrained(f, 0, 0, X) assert abs(res_uncon00[0] - opt) < 1e-6 assert abs(res_uncon00[1] - opt) < 1e-6 res_con010, dual = primal_dual_constrained(f, [], [], 0, 1, 0, X) assert abs(res_con010[0] - opt) < 1e-6 assert abs(res_con010[1] - opt) < 1e-6 solns = poly_solution_recovery.poly_solrec(dual) x_star = solns[0] gap = abs(f(x_star) - opt) assert gap < 1e-6
def test_conditional_sage_4(self): n = 4 x = standard_poly_monomials(n) f0 = -x[0] * x[2] ** 3 + 4 * x[1] * x[2] ** 2 * x[3] + 4 * x[0] * x[2] * x[3] ** 2 f1 = 2 * x[1] * x[3] ** 3 + 4 * x[0] * x[2] + 4 * x[2] ** 2 - 10 * x[1] * x[3] - 10 * x[3] ** 2 + 2 f = f0 + f1 sign_sym = [0.25 - x[i] ** 2 for i in range(n)] X = infer_domain(f, sign_sym, []) gts = [x[i] + 0.5 for i in range(n)] + [0.5 - x[i] for i in range(n)] dual = poly_constrained_relaxation(f, gts, [], X, p=1, q=2) dual.solve() expect = -3.180096 self.assertAlmostEqual(dual.value, expect, places=5) solns = poly_solution_recovery.poly_solrec(dual) self.assertGreaterEqual(len(solns), 1) x_star = solns[0] gap = f(x_star) - dual.value self.assertLessEqual(gap, 1e-5)
def test_conditional_sage_3(self): n = 5 x = standard_poly_monomials(n) f = 0 for i in range(n): sel = np.ones(n, dtype=bool) sel[i] = False f += 2 ** (n - 1) * np.prod(x[sel]) gts = [0.25 - x[i] ** 2 for i in range(n)] # -0.5 <= x[i] <= 0.5 for all i. opt = -3 expect = -5 X = infer_domain(f, gts, []) res_con010, dual = primal_dual_constrained(f, [], [], 0, 1, 0, X) assert abs(res_con010[0] - expect) < 1e-4 assert abs(res_con010[1] - expect) < 1e-4 solns = poly_solution_recovery.poly_solrec(dual) assert len(solns) > 0 x_star = solns[0] gap = abs(f(x_star) - opt) assert gap < 1e-4 pass
def test_conditional_sage_1(self): # Background # # This is Problem 1 from MCW2019. It appears in many papers on algorithms # for signomial progamming. All constraints are convex. # # Tests # # ell=0 and ell=3. Test for recovery of a feasible solution for # ell=0, and test for recovery of an optimal solution for ell=3. # # Notes # # ECOS can't solve the primal when ell > 0. Only try ell=3 if MOSEK is installed. # y = standard_sig_monomials(3) f = 0.5 * y[0] * y[1] ** -1 - y[0] - 5 * y[1] ** -1 gts = [100 - y[1] * y[2] ** -1 - y[1] - 0.05 * y[0] * y[2], y[0] - 70, y[1] - 1, y[2] - 0.5, 150 - y[0], 30 - y[1], 21 - y[2]] eqs = [] X = infer_domain(f, gts, eqs) vals, prob = primal_dual_vals(f, 0, X) expect = -147.85712 assert abs(vals[0] - expect) <= 1e-3 assert abs(vals[1] - expect) <= 1e-3 solutions = sig_solrec(prob) assert len(solutions) > 0 if cl.Mosek.is_installed(): vals, prob = primal_dual_vals(f, 3, X, solver='MOSEK') expect = -147.6666 assert abs(vals[0] - expect) <= 1e-3 assert abs(vals[1] - expect) <= 1e-3 solutions = sig_solrec(prob) assert len(solutions) > 0 x_star = solutions[0] gap = f(x_star) - prob.value assert abs(gap) <= 1e-3 pass
def test_conditional_constrained_sage_3(self): # Background # # This is a modification of Problem 10 from the 1978 paper by M. Rijckaert and X. Martens. # The bound constraints come from a different paper (but I dont recall where...). # We also add an additional trivially-valid constraint (simply to strengthen the Lagrange dual). # The optimal objective is reported in the literature as approximately -83.21. # # Tests - (p, q, ell) = (0, 1, 1) # # (1) Verify similar primal / dual objectives. # # (2) Recover a strictly feasible solution, within 0.7 % of optimality. # # Notes # # With (p, q, ell) = (0, 0, 2) (not shown here), we get a SAGE bound of -83.253. # If the (0,0,2) SAGE bound of -83.253 is to be believed, then the recovered solution # actually has a relative optimality gap of only 0.003 percent. # n = 3 x = standard_sig_monomials(n) f = 0.5 * x[0] * (x[1] ** -1) - x[0] - 5.0 * (x[1] ** -1) g = 1 - 0.01 * x[1] * (x[2] ** -1) - 0.01 * x[0] - 0.0005 * x[0] * x[2] g = 100.0 * g gts = [g, g * (x[1] ** -2), 1e2 - x[0], 1e2 - x[1], 1e2 - x[2], x[0] - 1, x[1] - 1, x[2] - 1] eqs = [] X = infer_domain(f, gts, eqs) p, q, ell = 0, 1, 1 vals, dual = constrained_primal_dual_vals(f, gts, eqs, p, q, ell, X, solver='MOSEK') assert abs(vals[0] - vals[1]) < 1e-4 assert abs(vals[0] - (-83.3235)) < 1e-4 solns = sig_solrec(dual, ineq_tol=0) assert (f(solns[0]) - dual.value) / abs(dual.value) < 0.007