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)
Exemple #3
0
    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}}}')
Exemple #4
0
    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)