def test_unconstrained_sage_2(self): # Background # # This is Example 2 from a 2018 paper by Murray, Chandrasekaran, and Wierman # (https://arxiv.org/pdf/1810.01614.pdf). # # Tests # # (1) Check that primal / dual objective are -\infty for ell == 0. # # (2) Check that primal / dual objectives are close to a reference value, for ell == 1. # # (3) Recover a globally optimal solution at ell == 1. # alpha = np.array([[0, 0], [1, 0], [0, 1], [1, 1], [0.5, 1], [1, 0.5]]) c = np.array([0, 1, 1, 1.9, -2, -2]) s = Signomial(alpha, c) expected = [-np.inf, -0.122211863] pd0, _ = primal_dual_vals(s, 0) assert pd0[0] == expected[0] and pd0[1] == expected[0] pd1, dual = primal_dual_vals(s, 1) assert abs(pd1[0] - expected[1]) < 1e-5 and abs(pd1[1] - expected[1]) < 1e-5 solns = sig_solrec(dual) assert s(solns[0]) < 1e-6 + dual.value
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_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_constrained_sage_1a(self): # Tests - (p, q, ell) = (0, 1, 0) # # (1) Verify that primal and dual objectives are close to a reference value. # # (2) Recover a solution (feasible up to tol 1e-7) with at most 0.01 percent optimality gap # f, gs = TestSAGERelaxations._constrained_sage_1() expected = -0.6147 actual, dual = constrained_primal_dual_vals(f, gs, [], p=0, q=1, ell=0, X=None) assert abs(actual[0] - expected) < 1e-4 and abs(actual[1] - expected) < 1e-4 solns = sig_solrec(dual, ineq_tol=1e-7) assert (f(solns[0]) - dual.value) / abs(dual.value) < 1e-4
def test_unconstrained_sage_1(self, presolve=False, compactdual=True, kernel_basis=False): # Background # # This is Example 1 from a 2018 paper by Murray, Chandrasekaran, and Wierman # (https://arxiv.org/pdf/1810.01614.pdf). # # Tests # # (1) Check that primal / dual objectives are close to a reference values, for ell \in {0, 1}. # # (2) Recover a globally optimal solution at ell == 1. # initial_presolve = sage_cones.SETTINGS['presolve_trivial_age_cones'] initial_compactdual = sage_cones.SETTINGS['compact_dual'] initial_kb = sage_cones.SETTINGS['kernel_basis'] cl.presolve_trivial_age_cones(presolve) cl.compact_sage_duals(compactdual) cl.kernel_basis_age_witnesses(kernel_basis) alpha = np.array([[0, 0], [1, 0], [0, 1], [1, 1], [0.5, 0], [0, 0.5]]) c = np.array([0, 3, 2, 1, -4, -2]) s = Signomial(alpha, c) expected = [-1.83333, -1.746505595] pd0, _ = primal_dual_vals(s, 0) self.assertAlmostEqual(pd0[0], expected[0], 4) self.assertAlmostEqual(pd0[1], expected[0], 4) pd1, dual = primal_dual_vals(s, 1) self.assertAlmostEqual(pd1[0], expected[1], 4) self.assertAlmostEqual(pd1[1], expected[1], 4) optsols = sig_solrec(dual) assert (s(optsols[0]) - dual.value) < 1e-6 cl.presolve_trivial_age_cones(initial_presolve) cl.compact_sage_duals(initial_compactdual) cl.kernel_basis_age_witnesses(initial_kb)
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
def test_unconstrained_sage_4(self, presolve=False, compactdual=False, kernel_basis=False): # Background # # This example was constructed soley as a test case for sageopt. # # Minimize s(x) = exp(3*x) - 4*exp(2*x) + 7*exp(x) + exp(-x), over x \in R. # # Tests # # (1) Check that primal / dual objectives are close to reference values, for ell \in {0, 1, 2}. # # (2) Recover a globally optimal solution from the dual relaxation, when ell == 3. # # Notes # # It may not be obvious, but the signomial "s" is actually convex! # initial_presolve = sage_cones.SETTINGS['presolve_trivial_age_cones'] initial_compactdual = sage_cones.SETTINGS['compact_dual'] initial_kb = sage_cones.SETTINGS['kernel_basis'] cl.presolve_trivial_age_cones(presolve) cl.compact_sage_duals(compactdual) cl.kernel_basis_age_witnesses(kernel_basis) s = Signomial.from_dict({(3,): 1, (2,): -4, (1,): 7, (-1,): 1}) expected = [3.464102, 4.60250026, 4.6217973] pds = [primal_dual_vals(s, ell) for ell in range(3)] for ell in range(3): assert abs(pds[ell][0][0] - expected[ell]) < 1e-5 assert abs(pds[ell][0][1] - expected[ell]) < 1e-5 dual = sig_relaxation(s, form='dual', ell=3) dual.solve(solver='ECOS', verbose=False) optsols = sig_solrec(dual) assert s(optsols[0]) < 1e-6 + dual.value cl.presolve_trivial_age_cones(initial_presolve) cl.compact_sage_duals(initial_compactdual) cl.kernel_basis_age_witnesses(initial_kb)