def test_construct_basis(self): # 2 variables, 3rd degree. Even and odd. x = Variable.multivariate('x', 2) degree = 3 basis = BasisVector.construct_basis(x, degree) basis_powers = [(0, 0), (1, 0), (0, 1), (2, 0), (0, 2), (1, 1), (3, 0), (0, 3), (2, 1), (1, 2)] self._test_basis_by_powers(x, basis, basis_powers) # 2 variables, 3rd degree. Even only. basis = BasisVector.construct_basis(x, degree, odd=False) basis_powers = [(0, 0), (2, 0), (0, 2), (1, 1)] self._test_basis_by_powers(x, basis, basis_powers) # 2 variables, 3rd degree. Odd only. basis = BasisVector.construct_basis(x, degree, even=False) basis_powers = [(1, 0), (0, 1), (3, 0), (0, 3), (2, 1), (1, 2)] self._test_basis_by_powers(x, basis, basis_powers) # 3 variables, 2nd degree. Even and odd. x = Variable.multivariate('x', 3) degree = 2 basis = BasisVector.construct_basis(x, degree) basis_powers = [(0, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1), (2, 0, 0), (0, 2, 0), (0, 0, 2), (1, 1, 0), (0, 1, 1), (1, 0, 1)] self._test_basis_by_powers(x, basis, basis_powers) # 3 variables, 2nd degree. Even only. basis = BasisVector.construct_basis(x, degree, odd=False) basis_powers = [(0, 0, 0), (2, 0, 0), (0, 2, 0), (0, 0, 2), (1, 1, 0), (0, 1, 1), (1, 0, 1)] self._test_basis_by_powers(x, basis, basis_powers) # 3 variables, 2nd degree. Odd only. basis = BasisVector.construct_basis(x, degree, even=False) basis_powers = [(1, 0, 0), (0, 1, 0), (0, 0, 1)] self._test_basis_by_powers(x, basis, basis_powers) # 0 degree. degree = 0 basis = BasisVector.construct_basis(x, degree) basis_powers = [(0, 0, 0)] self._test_basis_by_powers(x, basis, basis_powers) basis = BasisVector.construct_basis(x, degree, odd=False) self._test_basis_by_powers(x, basis, basis_powers) basis = BasisVector.construct_basis(x, degree, even=False) basis_powers = [] self._test_basis_by_powers(x, basis, basis_powers) # Negative degree. with self.assertRaises(ValueError): basis = BasisVector.construct_basis(x, -3) # Float degree. with self.assertRaises(ValueError): basis = BasisVector.construct_basis(x, 3.5)
def test_quadratic_form(self): for Vector in Vectors: x = Variable.multivariate('x', 2) basis = Vector.construct_basis(x, 1) Q = np.array([[1, 2, 3], [2, 4, 5], [3, 5, 6]]) p = Polynomial.quadratic_form(basis, Q) p_target = basis[0] * basis[0] + (basis[0] * basis[1]) * 4 + \ (basis[0] * basis[2]) * 6 + (basis[1] * basis[1]) * 4 + \ (basis[1] * basis[2]) * 10 + (basis[2] * basis[2]) * 6 self.assertEqual(p, p_target)
def test_multivariate(self): # Test the representation only. x = Variable.multivariate('x', 5) for i, xi in enumerate(x): self.assertTrue(xi.__repr__() == f'x_{{{i+1}}}')
class TestSosProgram(unittest.TestCase): x = Variable.multivariate('x', 2) zero = {xi: 0 for xi in x} one = {xi: 1 for xi in x} two = {xi: 2 for xi in x} def test_new_free_polynomial(self): for Vector in Vectors: # Fit free polynomial in 3 points. prog = SosProgram() basis = Vector.construct_basis(self.x, 3) poly, coef = prog.add_polynomial(basis) prog.add_linear_constraint(poly(self.zero) == 0) prog.add_linear_constraint(poly(self.one) == 1) prog.add_linear_constraint(poly(self.two) == 2) prog.solve() coef_opt = prog.substitute_minimizer(coef) poly_opt = prog.substitute_minimizer(poly) self.assertAlmostEqual(poly_opt(self.zero), 0, places=4) self.assertAlmostEqual(poly_opt(self.one), 1, places=4) self.assertAlmostEqual(poly_opt(self.two), 2, places=4) def test_new_sos_polynomial(self): # Fit free polynomial in 2 points, and minimize value at a third. for Vector in Vectors: # Normal polynomial. prog = SosProgram() basis = Vector.construct_basis(self.x, 3) poly, gram, cons = prog.add_sos_polynomial(basis) prog.add_linear_cost(poly(self.zero)) prog.add_linear_constraint(poly(self.one) == 1) prog.add_linear_constraint(poly(self.two) == 2) prog.solve() poly_opt = prog.substitute_minimizer(poly) self.assertAlmostEqual(prog.minimum(), 0, places=4) self.assertAlmostEqual(poly_opt(self.zero), 0, places=4) self.assertAlmostEqual(poly_opt(self.one), 1, places=4) self.assertAlmostEqual(poly_opt(self.two), 2, places=4) # Reconstruct polynomial from Gram matrix. gram_opt = prog.substitute_minimizer(gram) self.assertTrue(self._is_psd(gram_opt)) poly_opt_gram = Polynomial.quadratic_form(basis, gram_opt) self.assertAlmostEqual(poly_opt, poly_opt_gram) # Even polynomial. prog = SosProgram() poly, gram, cons = prog.add_even_sos_polynomial(basis) prog.add_linear_cost(poly(self.zero)) prog.add_linear_constraint(poly(self.one) == 1) prog.add_linear_constraint(poly(self.two) == 2) prog.solve() poly_opt = prog.substitute_minimizer(poly) self.assertAlmostEqual(prog.minimum(), 0, places=4) self.assertAlmostEqual(poly_opt(self.zero), 0, places=4) self.assertAlmostEqual(poly_opt(self.one), 1, places=4) self.assertAlmostEqual(poly_opt(self.two), 2, places=4) # Reconstruct polynomial from Gram matrices. gram_opt_e, gram_opt_o = [ prog.substitute_minimizer(gi) for gi in gram ] self.assertTrue(self._is_psd(gram_opt_e)) self.assertTrue(self._is_psd(gram_opt_o)) basis_e = [v for v in basis if v.is_even()] basis_o = [v for v in basis if v.is_odd()] poly_opt_gram = Polynomial.quadratic_form(basis_e, gram_opt_e) poly_opt_gram += Polynomial.quadratic_form(basis_o, gram_opt_o) self.assertAlmostEqual(poly_opt, poly_opt_gram, places=4) def test_add_sos_constraint(self): # Fit free polynomial in 2 points, and minimize value at a third. for Vector in Vectors: # Normal polynomial. prog = SosProgram() basis = Vector.construct_basis(self.x, 6) poly, coef = prog.add_polynomial(basis) gram = prog.add_sos_constraint(poly)[1] prog.add_linear_cost(poly(self.zero)) prog.add_linear_constraint(poly(self.one) == 1) prog.add_linear_constraint(poly(self.two) == 2) prog.solve() poly_opt = prog.substitute_minimizer(poly) self.assertAlmostEqual(prog.minimum(), 0, places=4) self.assertAlmostEqual(poly_opt(self.zero), 0, places=4) self.assertAlmostEqual(poly_opt(self.one), 1, places=4) self.assertAlmostEqual(poly_opt(self.two), 2, places=4) # Reconstruct polynomial from Gram matrix. gram_opt = prog.substitute_minimizer(gram) self.assertTrue(self._is_psd(gram_opt)) basis_half = Vector.construct_basis(self.x, 3) poly_opt_gram = Polynomial.quadratic_form(basis_half, gram_opt) self.assertAlmostEqual(poly_opt, poly_opt_gram) # Even polynomial. prog = SosProgram() basis = Vector.construct_basis(self.x, 6, odd=False) poly, coef = prog.add_polynomial(basis) gram = prog.add_sos_constraint(poly)[1] prog.add_linear_cost(poly(self.zero)) prog.add_linear_constraint(poly(self.one) == 1) prog.add_linear_constraint(poly(self.two) == 2) prog.solve() poly_opt = prog.substitute_minimizer(poly) self.assertAlmostEqual(prog.minimum(), 0, places=4) self.assertAlmostEqual(poly_opt(self.zero), 0, places=4) self.assertAlmostEqual(poly_opt(self.one), 1, places=4) self.assertAlmostEqual(poly_opt(self.two), 2, places=4) # Reconstruct polynomial from Gram matrices. gram_opt_e, gram_opt_o = [ prog.substitute_minimizer(gi) for gi in gram ] self.assertTrue(self._is_psd(gram_opt_e)) self.assertTrue(self._is_psd(gram_opt_o)) basis = Vector.construct_basis(self.x, 3) basis_e = [v for v in basis if v.is_even()] basis_o = [v for v in basis if v.is_odd()] poly_opt_gram = Polynomial.quadratic_form(basis_e, gram_opt_e) poly_opt_gram += Polynomial.quadratic_form(basis_o, gram_opt_o) self.assertAlmostEqual(poly_opt, poly_opt_gram, places=4) # Polynomial of odd degree. prog = SosProgram() basis = Vector.construct_basis(self.x, 3) poly, c = prog.add_polynomial(basis) with self.assertRaises(ValueError): prog.add_sos_constraint(poly) # Polynomial of length 0. prog = SosProgram() poly = Polynomial({}) with self.assertRaises(ValueError): prog.add_sos_constraint(poly) @staticmethod def _is_psd(A, tol=1e-7): return all(np.linalg.eig(A)[0] > -tol)