// (C) Copyright Jeremy Murphy 2015. // Use, modification and distribution are subject to the // Boost Software License, Version 1.0. (See accompanying file // LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) #include #define BOOST_TEST_MAIN #include #include #include #include #include #include #include using namespace boost::math; using namespace boost::math::tools; using namespace std; template struct answer { answer(std::pair< polynomial, polynomial > const &x) : quotient(x.first), remainder(x.second) {} polynomial quotient; polynomial remainder; }; boost::array const d3a = {{10, -6, -4, 3}}; boost::array const d3b = {{-7, 5, 6, 1}}; boost::array const d3c = {{10.0/3.0, -2.0, -4.0/3.0, 1.0}}; boost::array const d1a = {{-2, 1}}; boost::array const d2a = {{-2, 2, 3}}; boost::array const d2b = {{-7, 5, 6}}; boost::array const d2c = {{31, -21, -22}}; boost::array const d0a = {{6}}; boost::array const d0b = {{3}}; boost::array const d8 = {{-5, 2, 8, -3, -3, 0, 1, 0, 1}}; boost::array const d8b = {{0, 2, 8, -3, -3, 0, 1, 0, 1}}; boost::array const d6 = {{21, -9, -4, 0, 5, 0, 3}}; boost::array const d2 = {{-6, 0, 9}}; boost::array const d5 = {{-9, 0, 3, 0, -15}}; BOOST_AUTO_TEST_CASE( test_degree ) { polynomial const zero = zero_element(std::multiplies< polynomial >()); polynomial const a(d3a.begin(), d3a.end()); BOOST_CHECK_THROW(zero.degree(), std::logic_error); BOOST_CHECK_EQUAL(a.degree(), 3); } typedef boost::mpl::list test_types; BOOST_AUTO_TEST_CASE( test_division_over_field ) { polynomial const a(d3a.begin(), d3a.end()); polynomial const b(d1a.begin(), d1a.end()); polynomial const q(d2a.begin(), d2a.end()); polynomial const r(d0a.begin(), d0a.end()); polynomial const c(d3b.begin(), d3b.end()); polynomial const d(d2b.begin(), d2b.end()); polynomial const e(d2c.begin(), d2c.end()); polynomial const f(d0b.begin(), d0b.end()); polynomial const g(d3c.begin(), d3c.end()); polynomial const zero = zero_element(std::multiplies< polynomial >()); polynomial const one = identity_element(std::multiplies< polynomial >()); answer result = quotient_remainder(a, b); BOOST_CHECK_EQUAL(result.quotient, q); BOOST_CHECK_EQUAL(result.remainder, r); BOOST_CHECK_EQUAL(a, q * b + r); // Sanity check. result = quotient_remainder(a, c); BOOST_CHECK_EQUAL(result.quotient, f); BOOST_CHECK_EQUAL(result.remainder, e); BOOST_CHECK_EQUAL(a, f * c + e); // Sanity check. result = quotient_remainder(a, f); BOOST_CHECK_EQUAL(result.quotient, g); BOOST_CHECK_EQUAL(result.remainder, zero); BOOST_CHECK_EQUAL(a, g * f + zero); // Sanity check. // Check that division by a regular number gives the same result. BOOST_CHECK_EQUAL(a / 3.0, g); BOOST_CHECK_EQUAL(a % 3.0, zero); // Sanity checks. BOOST_CHECK_EQUAL(a / a, one); BOOST_CHECK_EQUAL(a % a, zero); // BOOST_CHECK_EQUAL(zero / zero, zero); // TODO } BOOST_AUTO_TEST_CASE( test_division_over_ufd ) { polynomial const zero = zero_element(std::multiplies< polynomial >()); polynomial const one = identity_element(std::multiplies< polynomial >()); polynomial const aa(d8.begin(), d8.end()); polynomial const bb(d6.begin(), d6.end()); polynomial const q(d2.begin(), d2.end()); polynomial const r(d5.begin(), d5.end()); answer result = quotient_remainder(aa, bb); BOOST_CHECK_EQUAL(result.quotient, q); BOOST_CHECK_EQUAL(result.remainder, r); // Sanity checks. BOOST_CHECK_EQUAL(aa / aa, one); BOOST_CHECK_EQUAL(aa % aa, zero); } BOOST_AUTO_TEST_CASE( test_gcd ) { /* NOTE: Euclidean gcd is not yet customized to return THE greatest * common polynomial divisor. If d is THE greatest common divisior of u and * v, then gcd(u, v) will return d or -d according to the algorithm. * By convention, it should return d, as for example Maxima and Wolfram * Alpha do. * This test is an example of the fact that it returns -d. */ boost::array const d8 = {{105, 278, -88, -56, 16}}; boost::array const d6 = {{70, 232, -44, -64, 16}}; boost::array const d2 = {{-35, 24, -4}}; polynomial const u(d8.begin(), d8.end()); polynomial const v(d6.begin(), d6.end()); polynomial const w(d2.begin(), d2.end()); polynomial const d = gcd(u, v); BOOST_CHECK_EQUAL(w, d); } // Sanity checks to make sure I didn't break it. BOOST_AUTO_TEST_CASE_TEMPLATE( test_addition, T, test_types ) { polynomial const a(d3a.begin(), d3a.end()); polynomial const b(d1a.begin(), d1a.end()); polynomial const zero = zero_element(multiplies< polynomial >()); polynomial result = a + b; // different degree boost::array tmp = {{8, -5, -4, 3}}; polynomial expected(tmp.begin(), tmp.end()); BOOST_CHECK_EQUAL(result, expected); BOOST_CHECK_EQUAL(a + zero, a); BOOST_CHECK_EQUAL(a + b, b + a); } BOOST_AUTO_TEST_CASE_TEMPLATE( test_subtraction, T, test_types ) { polynomial const a(d3a.begin(), d3a.end()); polynomial const zero = zero_element(multiplies< polynomial >()); BOOST_CHECK_EQUAL(a - T(0), a); BOOST_CHECK_EQUAL(T(0) - a, -a); BOOST_CHECK_EQUAL(a - zero, a); BOOST_CHECK_EQUAL(zero - a, -a); BOOST_CHECK_EQUAL(a - a, zero); } BOOST_AUTO_TEST_CASE_TEMPLATE( test_multiplication, T, test_types ) { polynomial const a(d3a.begin(), d3a.end()); polynomial const b(d1a.begin(), d1a.end()); polynomial const zero = zero_element(multiplies< polynomial >()); BOOST_CHECK_EQUAL(a * T(0), zero); BOOST_CHECK_EQUAL(a * zero, zero); BOOST_CHECK_EQUAL(zero * T(0), zero); BOOST_CHECK_EQUAL(zero * zero, zero); BOOST_CHECK_EQUAL(a * b, b * a); } BOOST_AUTO_TEST_CASE_TEMPLATE( test_arithmetic_relations, T, test_types ) { polynomial const a(d8b.begin(), d8b.end()); polynomial const b(d1a.begin(), d1a.end()); BOOST_CHECK_EQUAL(a * T(2), a + a); BOOST_CHECK_EQUAL(a - b, -b + a); BOOST_CHECK_EQUAL(a * 0.5, a / T(2)); BOOST_CHECK_EQUAL(a, (a * a) / a); BOOST_CHECK_EQUAL(a, (a / a) * a); }