Exemple #1
0
 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
Exemple #2
0
 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
Exemple #3
0
 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
Exemple #4
0
 def test_constrained_sage_2(self):
     # Background
     #
     #       This is a signomial formulation of a nonnegative polynomial optimization problem.
     #
     #       The problem can be found on page 16 of the gloptipoly3 manual
     #                   http://homepages.laas.fr/henrion/papers/gloptipoly3.pdf
     #       among other places. The optimal objective is -4.
     #
     # Tests - (p, q, ell) = (0, 1, 0)
     #
     #       (1) Check for similar primal / dual objectives.
     #
     x = standard_sig_monomials(3)
     f = -2 * x[0] + x[1] - x[2]
     g1 = Signomial.from_dict({(0, 0, 0): 24,
                     (1, 0, 0): -20,
                     (0, 1, 0): 9,
                     (0, 0, 1): -13,
                     (2, 0, 0): 4,
                     (1, 1, 0): -4,
                     (1, 0, 1): 4,
                     (0, 2, 0): 2,
                     (0, 1, 1): -2,
                     (0, 0, 2): 2})
     g2 = 4 - x[0] - x[1] - x[2]
     g3 = 6 - 3*x[1] - x[2]
     g4 = 2 - x[0]
     g5 = 3 - x[2]
     gts = [g1, g2, g3, g4, g5]
     res01, _ = constrained_primal_dual_vals(f, gts, [], p=0, q=1, ell=0, X=None)
     expect = -6
     assert abs(res01[0] - expect) < 1e-4
     assert abs(res01[1] - expect) < 1e-4
     assert abs(res01[0] - res01[1]) < 1e-5
Exemple #5
0
 def test_exponentiation(self):
     x = standard_sig_monomials(2)
     y0 = (x[0] - x[1])**2
     y1 = x[0]**2 - 2 * x[0] * x[1] + x[1]**2
     assert y0 == y1
     z0 = x[0]**0.5
     z1 = Signomial.from_dict({(0.5, 0): 1})
     assert z0 == z1
Exemple #6
0
 def test_invalid_signomial_operations(self):
     x = standard_sig_monomials(2)
     y = standard_sig_monomials(1)
     try:
         s = x[0] + y[0]
         assert False
     except RuntimeError as err:
         err_str = str(err)
         assert 'Cannot add' in err_str
     try:
         s = x[0] * y[0]
         assert False
     except RuntimeError as err:
         err_str = str(err)
         assert 'Cannot multiply' in err_str
     s = sum(x)
     try:
         t = s**0.5
         assert False
     except ValueError as err:
         err_str = str(err)
         assert 'Only signomials with exactly one term' in err_str
     z = cl.Variable()
     s = 0 * s + z  # a Signomial, with only a constant term.
     try:
         t = s**2
         assert False
     except RuntimeError as err:
         err_str = str(err)
         assert 'Cannot exponentiate signomials with symbolic coefficients' in err_str
     try:
         y = x[0]**x[1]
         assert False
     except RuntimeError as err:
         err_str = str(err)
         assert 'Cannot raise a signomial to non-numeric powers.' == err_str
     pass
Exemple #7
0
 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
Exemple #8
0
 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_composition_sigs(self):
     p = Polynomial.from_dict({
         (1, ): 2,
         (0, ): -1
     })  # represents lambda x: 2*x - 1
     s = Signomial.from_dict({(2, ): -1, (0, ): 1})
     f = p(s)  # lambda x: -2*exp(x) + 1
     self.assertAlmostEqual(f(0.5), -2 * np.exp(1.0) + 1, places=4)
     self.assertAlmostEqual(f(1), -2 * np.exp(2.0) + 1, places=4)
     p = np.prod(standard_poly_monomials(3))
     exp_x = standard_sig_monomials(2)
     sig_vec = np.array([exp_x[0], exp_x[0] - exp_x[1], 1.0 / exp_x[1]])
     f = p(sig_vec)
     self.assertEqual(f.n, 2)
     self.assertEqual(f(np.array([1, 1])), 0)
     x_test = np.array([-3, 3])
     self.assertAlmostEqual(f(x_test),
                            np.exp(-6) * (np.exp(-3) - np.exp(3)),
                            places=4)
Exemple #10
0
 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
Exemple #11
0
 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