def test_integral_of_zero(self):
        """Test that integral of a zero polynomial is zero."""
        p = Polynomial()
        z = ZeroPolynomial()

        self.assertEqual(0, z.integral(-1000, 1000))
        self.assertEqual(0, p.integral(-1000, 1000))
    def test_derivative_of_zero_is_zero(self):
        """Test that the derivative of the zero polynomial is the zero poly."""
        p = ZeroPolynomial()
        expect = ZeroPolynomial()

        result = p.derivative

        self._assert_polynomials_are_the_same(expect, result)
    def test_zero_polynomial_hash_equal(self):
        """Test that two zero polynomials have equal hash value."""
        z1 = ZeroPolynomial()
        z2 = ZeroPolynomial()

        h1 = hash(z1)
        h2 = hash(z2)

        self.assertEqual(h1, h2)
        self.assertEqual({h1}, {h1, h2})
    def test_mul_zero_poly_returns_most_permissive(self):
        """Test that multiplication never reduces permissiveness."""
        a = Polynomial(1, 2, 3) * ZeroPolynomial()
        b = Monomial(1, 2) * ZeroPolynomial()
        c = Constant(5) * ZeroPolynomial()
        d = ZeroPolynomial() * ZeroPolynomial()

        self.assertIsInstance(a, Polynomial)
        self.assertIsInstance(b, Monomial)
        self.assertIsInstance(c, Constant)
        self.assertIsInstance(d, ZeroPolynomial)
    def test_pow_monomial(self):
        """Test power against various Monomial subclasses."""
        c = Constant(5)
        ec = Constant(25)
        m = Monomial(5, 10)
        em = Monomial(25, 20)
        z = ZeroPolynomial()
        ez = ZeroPolynomial()

        self._assert_polynomials_are_the_same(ec, c**2)
        self._assert_polynomials_are_the_same(em, m**2)
        self._assert_polynomials_are_the_same(ez, z**2)
    def test_lshift_zero_monomial(self):
        """Test that lshift on a zero monomial behaves correctly."""
        m = Monomial(0, 1) << 5
        c = Constant(0) << 10
        z = ZeroPolynomial() << 2
        em = Monomial(0, 0)
        ec = Constant(0)
        ez = ZeroPolynomial()

        self._assert_polynomials_are_the_same(em, m)
        self._assert_polynomials_are_the_same(ec, c)
        self._assert_polynomials_are_the_same(ez, z)
    def test_permissive_zero_zero_polynomial(self):
        """Test that permissiveness doesn't decrease with ZeroPolynomial."""
        a = Polynomial(1, 2, 3)
        b = Monomial(1, 2)
        c = Constant(5)
        d = ZeroPolynomial()

        zz = ZeroPolynomial()

        self.assertIsInstance(a * zz, Polynomial)
        self.assertIsInstance(b * zz, Monomial)
        self.assertIsInstance(c * zz, Constant)
        self.assertIsInstance(d * zz, ZeroPolynomial)
    def test_mul_zero_result_zero(self):
        """Test that multiplying by zero equals zero."""
        coeffs = [1, 1, 1]
        p1 = Polynomial(coeffs)
        p2 = Polynomial(coeffs)
        p3 = Polynomial(coeffs)
        p4 = Polynomial(coeffs)
        z0 = ZeroPolynomial()
        z1 = Polynomial.zero_instance()

        # Multiplication will return the most permissive
        # class (eg. which allows the most mutability).
        result1 = p1 * z0
        result2 = z0 * p2
        p1 *= z0
        p2 *= 0
        p3 *= 0.0
        p4 *= 0j

        self._assert_polynomials_are_the_same(z1, result1)
        self._assert_polynomials_are_the_same(z1, result2)
        self._assert_polynomials_are_the_same(z1, p1)
        self._assert_polynomials_are_the_same(z1, p2)
        self._assert_polynomials_are_the_same(z1, p3)
        self._assert_polynomials_are_the_same(z1, p4)
    def test_derivative_of_constant_equals_zero(self):
        """Test that the derivative of a Constant is equal to the zero poly."""
        c = Constant(1)
        expect = ZeroPolynomial()

        result = c.derivative

        self.assertEqual(expect, result)
    def test_zero_polynomial_equals_zero(self):
        """Test that ZeroPolynomial() == Polynomial() == Constant(0) == 0."""
        z = ZeroPolynomial()
        p = Polynomial()
        c = Constant(0)

        self.assertTrue(c == p == z == 0)
        self.assertTrue(c == p == z == 0.0)
        self.assertTrue(c == p == z == 0.0j)
    def test_zero_polynomial_hash_equal_to_empty_frozen_polynomal_hash(self):
        """Test that hash(ZeroPolynomial()) == hash(FrozenPolynomial())."""
        z = ZeroPolynomial()
        f = FrozenPolynomial()

        hz = hash(z)
        hf = hash(f)

        self.assertEqual(hz, hf)
    def test_degree_of_zero_is_minus_infinity(self):
        """Test that the degree of the zero poly is minus infinity."""
        z = ZeroPolynomial()
        p = Polynomial()
        c = Constant(0)
        expect = -inf

        self.assertEqual(expect, z.degree)
        self.assertEqual(expect, p.degree)
        self.assertEqual(expect, c.degree)
    def test_mul_polymial_returns_most_permissive(self):
        """Test that multiplication never reduces permissiveness."""
        a = Polynomial(1, 2, 3) * Polynomial(3, 4, 1)
        b = Monomial(1, 3) * Polynomial(5, 1, 2)
        c = Constant(5) * Polynomial(6, 8, 1)
        d = ZeroPolynomial() * Polynomial(9, 2, 7)

        self.assertIsInstance(a, Polynomial)
        self.assertIsInstance(b, Polynomial)
        self.assertIsInstance(c, Polynomial)
        self.assertIsInstance(d, Polynomial)
    def test_subtraction_to_zero_properties_change_accordingly(self):
        """Test that the properties change when subtraction sets self to 0."""
        coeffs = [1, 2]
        p1 = Polynomial(coeffs)
        p2 = Polynomial(coeffs)
        expect = Polynomial()

        a = p1 - p2

        self._assert_polynomials_are_the_same(expect, a)
        self.assertEqual(ZeroPolynomial(), a)
    def test_pow_two_case(self):
        """Test pow ** 2."""
        c = Constant(5)
        m = Monomial(5, 10)
        z = ZeroPolynomial()
        p = Polynomial(1, 2, 3)

        self._assert_polynomials_are_the_same(c * c, c**2)
        self._assert_polynomials_are_the_same(m * m, m**2)
        self._assert_polynomials_are_the_same(z * z, z**2)
        self._assert_polynomials_are_the_same(p * p, p**2)
    def test_frozen_vector_immutable(self):
        """Test that frozen vectors can't be modified."""
        a = ZeroPolynomial()
        b = FrozenPolynomial(1, 2, 3)

        def set_item(obj, index, value):
            obj[index] = value

        possible_errs = (TypeError, AttributeError)
        self.assertRaises(possible_errs, set_item, a._vector, 0, 5)
        self.assertRaises(possible_errs, set_item, b._vector, 0, 5)
    def test_pow_one_case(self):
        """Tests pow ** 1 returns a copy of the polynomial."""
        c = Constant(5)
        m = Monomial(5, 10)
        z = ZeroPolynomial()
        p = Polynomial(1, 2, 3)

        self._assert_polynomials_are_the_same(c, c**1)
        self._assert_polynomials_are_the_same(m, m**1)
        self._assert_polynomials_are_the_same(z, z**1)
        self._assert_polynomials_are_the_same(p, p**1)
    def test_permissive_zero_constant(self):
        """Test that permissiveness doesn't decrease with Constant zero."""
        a = Polynomial(1, 2, 3)
        b = Monomial(1, 2)
        c = Constant(5)
        d = ZeroPolynomial()

        zc = Constant(0)

        self.assertIsInstance(a * zc, Polynomial)
        self.assertIsInstance(b * zc, Monomial)
        self.assertIsInstance(c * zc, Constant)
        self.assertIsInstance(d * zc, Constant)
    def test_permissive_zero_monomial(self):
        """Test that permissiveness doesn't decrease with Monomial zero."""
        a = Polynomial(1, 2, 3)
        b = Monomial(1, 2)
        c = Constant(5)
        d = ZeroPolynomial()

        zm = Monomial(0, 0)

        self.assertIsInstance(a * zm, Polynomial)
        self.assertIsInstance(b * zm, Monomial)
        self.assertIsInstance(c * zm, Monomial)
        self.assertIsInstance(d * zm, Monomial)
    def test_ipow_matches_pow(self):
        """Test that x **= y behaves as expected."""
        to_test = [
            Polynomial(1, 2, 3),
            Monomial(1, 2),
            Constant(5),
            ZeroPolynomial(),
        ]

        for val in to_test:
            copy_val = deepcopy(val)
            copy_val **= 5
            self._assert_polynomials_are_the_same(val**5, copy_val)
 def test_shift_zero_polynomial(self):
     """Test that shifting zero polynomial does nothing."""
     z = ZeroPolynomial()
     z1 = z << 1
     z2 = z >> 1
     z3 = z << -1
     z4 = z >> -1
     z5 = ZeroPolynomial()
     z6 = ZeroPolynomial()
     z7 = ZeroPolynomial()
     z8 = ZeroPolynomial()
     z5 <<= 1
     z6 >>= 1
     z7 <<= -1
     z8 >>= -1
     self._assert_polynomials_are_the_same(z, z1)
     self._assert_polynomials_are_the_same(z, z2)
     self._assert_polynomials_are_the_same(z, z3)
     self._assert_polynomials_are_the_same(z, z4)
     self._assert_polynomials_are_the_same(z, z5)
     self._assert_polynomials_are_the_same(z, z6)
     self._assert_polynomials_are_the_same(z, z7)
     self._assert_polynomials_are_the_same(z, z8)
    def test_pow_by_non_integer(self):
        """Test that pow by non-integer type is not possible."""
        to_test = [
            Polynomial(1, 2, 3),
            Monomial(1, 2),
            Constant(5),
            ZeroPolynomial(),
            QuadraticTrinomial(1, 3, 7),
            LinearBinomial(9, 2),
        ]

        for val in to_test:
            self.assertRaises(ValueError, val.__pow__, 1.2)
            self.assertRaises(ValueError, val.__ipow__, 1.5)
    def test_pos(self):
        """Test that a Polynomial is equal to its positive version."""
        a = Polynomial(1, 2, 3)
        b = Monomial(1, 2)
        c = Constant(5)
        d = ZeroPolynomial()
        e = QuadraticTrinomial(1, 3, 7)
        f = LinearBinomial(9, 2)

        self._assert_polynomials_are_the_same(a, +a)
        self._assert_polynomials_are_the_same(b, +b)
        self._assert_polynomials_are_the_same(c, +c)
        self._assert_polynomials_are_the_same(d, +d)
        self._assert_polynomials_are_the_same(e, +e)
        self._assert_polynomials_are_the_same(f, +f)
    def test_pow_zero_case(self):
        """Test pow ** 0 returns 1."""
        one = Constant(1)
        m_one = Monomial(1, 0)
        c = Constant(5)
        m = Monomial(5, 10)
        mz = Monomial(0, 1)
        z = ZeroPolynomial()
        p = Polynomial(1, 2, 3)

        self._assert_polynomials_are_the_same(one, c**0)
        self._assert_polynomials_are_the_same(m_one, m**0)
        self._assert_polynomials_are_the_same(m_one, mz**0)
        self._assert_polynomials_are_the_same(one, z**0)
        self._assert_polynomials_are_the_same(one, p**0)
    def test_div_by_zero(self):
        """Test that division by 0 is not possible."""
        to_test = [
            Polynomial(1, 2, 3),
            Monomial(1, 2),
            Constant(5),
            ZeroPolynomial(),
            QuadraticTrinomial(1, 3, 7),
            LinearBinomial(9, 2),
        ]

        for val in to_test:
            self.assertRaises(ZeroDivisionError, val.__floordiv__, 0)
            self.assertRaises(ZeroDivisionError, val.__ifloordiv__, 0)
            self.assertRaises(ZeroDivisionError, val.__mod__, 0)
            self.assertRaises(ZeroDivisionError, val.__imod__, 0)
            self.assertRaises(ZeroDivisionError, val.__divmod__, 0)
    def test_inequality(self):
        """Test that distinct values do not equal other."""
        to_test = [
            Polynomial(1, 2, 3),
            Monomial(1, 2),
            Constant(5),
            ZeroPolynomial(),
            QuadraticTrinomial(1, 3, 7),
            LinearBinomial(9, 2), 7
        ]

        for i, lhs in enumerate(to_test):
            for j, rhs in enumerate(to_test):
                if i == j:
                    self.assertTrue(lhs == lhs)
                    self.assertFalse(lhs != lhs)
                else:
                    self.assertFalse(lhs == rhs)
                    self.assertNotEqual(lhs, rhs)
    def test_add_zero_result_the_same(self):
        """Test that adding zero does not change the polynomial."""
        coeffs = [1, 1, 1]
        p1 = Polynomial(coeffs)
        p2 = Polynomial(coeffs)
        p3 = Polynomial(coeffs)
        p4 = Polynomial(coeffs)
        z = ZeroPolynomial()
        expect = Polynomial(coeffs)

        result1 = p1 + z
        result2 = z + p1
        p1 += z
        p2 += 0
        p3 += 0.0
        p4 += 0j

        self._assert_polynomials_are_the_same(p1, result1)
        self._assert_polynomials_are_the_same(p1, result2)
        self._assert_polynomials_are_the_same(expect, p1)
        self._assert_polynomials_are_the_same(expect, p2)
        self._assert_polynomials_are_the_same(expect, p3)
        self._assert_polynomials_are_the_same(expect, p4)
    def test_ipow_zero_gives_one(self):
        """Test that x **= 0 returns an appropriate 1 polynomial."""
        to_test = [
            Polynomial(1, 2, 3),
            Monomial(1, 2),
            Constant(5),
            ZeroPolynomial(),
            QuadraticTrinomial(1, 3, 7),
            LinearBinomial(9, 2),
        ]

        one_maps = {
            Polynomial: Polynomial(1),
            Monomial: Monomial(1, 0),
            Constant: Constant(1),
            ZeroPolynomial: Constant(1),
            QuadraticTrinomial: Polynomial(1),
            LinearBinomial: Polynomial(1),
        }

        for val in to_test:
            expected = one_maps[type(val)]
            val **= 0
            self._assert_polynomials_are_the_same(expected, val)
 def test_zero_polynomial_conversions(self):
     """Test that converting ZeroPolynomial to numerical types yields 0."""
     z = ZeroPolynomial()
     self.assertEqual(0, int(z))
     self.assertEqual(0.0, float(z))
     self.assertEqual(0j, complex(z))
 def test_zero_const_is_zero(self):
     """Test that ZeroPolynomial.const is always 0."""
     self.assertEqual(0, ZeroPolynomial().const)